<!DOCTYPE html>
<html lang="zh-cn">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
  <meta name="theme-color" content="#3367D6"/>
  <link rel="apple-touch-icon" href="/icons-192.png">
  <link rel="manifest" href="/manifest.json">
  <link rel="stylesheet" href="/lib/google-code-prettify/themes/tomorrow-night.css">
  <script type="text/javascript" src="/lib/google-code-prettify/src/prettify.js"></script>
  
  <meta name="generator" content="Hexo 5.4.2">

  
    <meta name="description" content="觉宇宙之无穷，识盈虚之有数">
  

  

  
    <meta name="author" content="RocPengHua">
  

  

  

  <title>23中设计模式学习 | 小鹏驿站</title>

  

  
    <link rel="shortcut icon" href="/favicon.ico">
  

  

  
<link rel="stylesheet" href="/css/style.css">

</head>
<body onload="PR.prettyPrint()">
  <div class="root-container">
    
<!-- header container -->
<header class="header-container post">
  
    <div class="post-image" style="background-image: url(&#39;https://api.lixingyong.com/api/images?postid=f121b1&amp;type=url&amp;itype=image&#39;)"></div>
  
  <!-- navbar -->
<nav class="navbar">
  <div class="navbar-content">
    <!-- logo -->
    <div class="navbar-logo">
      <a href="/">
        
          小鹏驿站
        
      </a>
    </div>
    <!-- link -->
    <div class="navbar-link">
      <div class="navbar-btn">
        <div></div>
        <div></div>
        <div></div>
      </div>
      <ul class="navbar-list">
        
              <li class="navbar-list-item">
                <a href="/">
                  <span class="faa-parent animated-hover">
                    <i class="fa  fa-home faa-shake" aria-hidden="true"></i>
                    首页
                  </span>
                </a>
                
              </li>
            
              <li class="navbar-list-item">
                <a href="/archives">
                  <span class="faa-parent animated-hover">
                    <i class="fa  fa-archive faa-shake" aria-hidden="true"></i>
                    归档
                  </span>
                </a>
                
              </li>
            
              <li class="navbar-list-item">
                <a href="/categories">
                  <span class="faa-parent animated-hover">
                    <i class="fa  fa-folder faa-shake" aria-hidden="true"></i>
                    分类
                  </span>
                </a>
                
                  <ul class="sub-menu">
                    
                      <li>
                        <a href="/categories/%E5%90%8E%E7%AB%AF/">
                          <i class="fa fa-etsy" aria-hidden="true"></i>
                          后端
                        </a>
                      </li>
                    
                      <li>
                        <a href="/categories/%E5%89%8D%E7%AB%AF/">
                          <i class="fa fa-grav" aria-hidden="true"></i>
                          前端
                        </a>
                      </li>
                    
                      <li>
                        <a href="/categories/%E8%BD%AF%E4%BB%B6/">
                          <i class="fa fa-key" aria-hidden="true"></i>
                          软件
                        </a>
                      </li>
                    
                      <li>
                        <a href="/categories/%E7%AE%97%E6%B3%95/">
                          <i class="fa fa-glass" aria-hidden="true"></i>
                          算法
                        </a>
                      </li>
                    
                      <li>
                        <a href="/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/">
                          <i class="fa fa-database" aria-hidden="true"></i>
                          数据库
                        </a>
                      </li>
                    
                      <li>
                        <a href="/categories/%E4%B8%AD%E9%97%B4%E4%BB%B6/">
                          <i class="fa fa-arrows-alt" aria-hidden="true"></i>
                          中间件
                        </a>
                      </li>
                    
                      <li>
                        <a href="/categories/%E9%97%AE%E9%A2%98/">
                          <i class="fa fa-telegram" aria-hidden="true"></i>
                          问题
                        </a>
                      </li>
                    
                      <li>
                        <a href="/categories/%E9%97%B2%E8%B0%88/">
                          <i class="fa fa-vcard" aria-hidden="true"></i>
                          闲谈
                        </a>
                      </li>
                    
                  </ul>
                
              </li>
            
              <li class="navbar-list-item">
                <a href="/tags">
                  <span class="faa-parent animated-hover">
                    <i class="fa  fa-tags" aria-hidden="true"></i>
                    标签
                  </span>
                </a>
                
                  <ul class="sub-menu">
                    
                      <li>
                        <a href="/tags/%E5%8A%A0%E5%AF%86/">
                          <i class="fa fa-wpexplorer" aria-hidden="true"></i>
                          加密
                        </a>
                      </li>
                    
                      <li>
                        <a href="/tags/idea/">
                          <i class="fa fa-eercast" aria-hidden="true"></i>
                          idea
                        </a>
                      </li>
                    
                      <li>
                        <a href="/tags/java/">
                          <i class="fa fa-coffee" aria-hidden="true"></i>
                          java
                        </a>
                      </li>
                    
                      <li>
                        <a href="/tags/mysql/">
                          <i class="fa fa-database" aria-hidden="true"></i>
                          mysql
                        </a>
                      </li>
                    
                      <li>
                        <a href="/tags/oracle/">
                          <i class="fa fa-database" aria-hidden="true"></i>
                          oracle
                        </a>
                      </li>
                    
                      <li>
                        <a href="/tags/spring/">
                          <i class="fa fa-leaf" aria-hidden="true"></i>
                          spring
                        </a>
                      </li>
                    
                      <li>
                        <a href="/tags/redis/">
                          <i class="fa fa-fire" aria-hidden="true"></i>
                          redis
                        </a>
                      </li>
                    
                      <li>
                        <a href="/tags/mongodb/">
                          <i class="fa fa-database" aria-hidden="true"></i>
                          mongodb
                        </a>
                      </li>
                    
                      <li>
                        <a href="/tags/rocketmq/">
                          <i class="fa fa-random" aria-hidden="true"></i>
                          rocketmq
                        </a>
                      </li>
                    
                      <li>
                        <a href="/tags/kafka/">
                          <i class="fa fa-random" aria-hidden="true"></i>
                          kafka
                        </a>
                      </li>
                    
                  </ul>
                
              </li>
            
              <li class="navbar-list-item">
                <a href="/music">
                  <span class="faa-parent animated-hover">
                    <i class="fa  fa-music" aria-hidden="true"></i>
                    音乐
                  </span>
                </a>
                
              </li>
            
              <li class="navbar-list-item">
                <a href="/links">
                  <span class="faa-parent animated-hover">
                    <i class="fa  fa-link" aria-hidden="true"></i>
                    友链
                  </span>
                </a>
                
              </li>
            
              <li class="navbar-list-item">
                <a href="/about">
                  <span class="faa-parent animated-hover">
                    <i class="fa  fa-signing" aria-hidden="true"></i>
                    关于
                  </span>
                </a>
                
              </li>
            
      </ul>
    </div>
  </div>
</nav>

  
  <span class="local-search local-search-google local-search-plugin" style="left: calc(50% - 200px);top: 0px;;position:absolute;z-index:2;">
      <input type="search" placeholder="小鹏驿站" id="local-search-input" class="local-search-input-cls" style="">
      <div id="local-search-result" class="local-search-result-cls"></div>
  </span>


  
  

  
  

  
  

  
  

  
  
    <div class="header-content">
      <div class="post-text layout-block">
        <div class="layout-margin">
          <h1 class="title-wrap" title="觉宇宙之无穷，识盈虚之有数">23中设计模式学习</h1>
          <h2 class="title-sub-wrap">
            <strong>RocPengHua</strong>
            <span>发布于</span>
            <time  class="article-date" datetime="2023-02-20T13:46:26.000Z" itemprop="datePublished">2023-02-20</time>
          </h2>
          <ul class="wrap-list dark">
  
    <li><a href="/categories/%E6%8A%80%E6%9C%AF/">📒 技术</a></li>
  
</ul>
          <ul class="wrap-list dark">
  
</ul>
        </div>
      </div>
    </div>
  

  
  
  
</header>

    <!-- 文章 -->

<!-- 文章内容 -->
<div class="body-container">
  <article class="content-container layout-block post-container">
    <div class="widget-info">
      <section class="widget-author widget-item layout-margin content-padding--primary soft-size--large soft-style--box">
  <div class="widget-body">
    
      <img src="/images/p.jpg" class="soft-size--round soft-style--box" alt="RocPengHua">
    
    
      <h2>RocPengHua</h2>
    
    
      <p>天天向上</p>
    

    <div class="count-box">
      <div class="count-box--item">
        <svg class="icon icon-article" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <path d="M240.51564747 647.74217627h196.07203239c16.59071043 0 30.16492806-13.57421762 30.16492805-30.16492806V165.10332731c0-33.18142087-30.16492806-60.32985613-60.32985612-60.32985611H245.04038668C225.43318342 104.7734712 210.35071939 119.85593522 210.35071939 139.46313845V617.57724821c0 16.59071043 13.57421762 30.16492806 30.16492808 30.16492806z m663.62841731-452.47392089v482.63884894c0 33.18142087-27.14843525 60.32985613-60.32985612 60.32985613H180.18579134c-33.18142087 0-60.32985613-27.14843525-60.32985612-60.32985613V195.26825538c-49.77213131 0-90.49478418 40.72265287-90.49478417 90.49478417v452.4739209c0 49.77213131 40.72265287 90.49478418 90.49478417 90.49478417h286.56681657c16.59071043 0 30.16492806 13.57421762 30.16492807 30.16492807s13.57421762 30.16492806 30.16492805 30.16492806h90.49478418c16.59071043 0 30.16492806-13.57421762 30.16492805-30.16492806s13.57421762-30.16492806 30.16492807-30.16492807h286.56681657c49.77213131 0 90.49478418-40.72265287 90.49478417-90.49478417V285.76303955c0-49.77213131-40.72265287-90.49478418-90.49478417-90.49478417zM587.41232014 647.74217627h191.54729318c19.60720323 0 34.68966726-15.08246403 34.68966729-34.68966727V134.93839925c0-16.59071043-13.57421762-30.16492806-30.16492808-30.16492805H617.57724821c-30.16492806 0-60.32985613 27.14843525-60.32985612 60.32985611v452.4739209c0 16.59071043 13.57421762 30.16492806 30.16492805 30.16492806z" fill="currentColor"></path>
</svg>
        <span>118</span>
      </div>
      <div class="count-box--item">
        <svg class="icon icon-categories" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <path d="M900.3614811 257.09082106h-339.81629553l-67.96326003-101.9448889c-19.41807444-29.12711113-48.54518557-43.69066667-82.52681443-43.69066667H123.6385189c-53.39970333 0-97.09036999 43.69066667-97.09037113 97.09036999v582.54222222c0 53.39970333 43.69066667 97.09036999 97.09037113 97.09037002h776.7229622c53.39970333 0 97.09036999-43.69066667 97.09037113-97.09037002V354.18119104c0-53.39970333-43.69066667-97.09036999-97.09037113-97.09036998z m-97.09036999 242.72592554H220.72888889c-24.27259221 0-48.54518557-24.27259221-48.54518556-48.54518556s24.27259221-48.54518557 48.54518556-48.54518444h582.54222222c24.27259221 0 48.54518557 24.27259221 48.54518556 48.54518444s-24.27259221 48.54518557-48.54518556 48.54518556z" fill="currentColor"></path>
</svg>
        16
      </div>
      <div class="count-box--item">
        <svg class="icon icon-tags" viewBox="0 0 1098 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <path d="M283.42180005 272q0-28.38857157-20.09142843-48.48000001t-48.47999998-20.09142842-48.48000002 20.09142842-20.09142846 48.48000001 20.09142846 48.48 48.48000002 20.09142843 48.47999998-20.09142843 20.09142843-48.48zM855.0332285 580.57142843q0 28.38857157-19.81714313 48.2057147l-263.03999997 263.58857157q-20.9142853 19.81714313-48.75428534 19.81714312-28.38857157 0-48.20571468-19.81714312l-383.04-383.58857157q-20.36571468-19.81714313-34.55999999-54.10285688t-14.19428534-62.6742853l0-222.85714313q0-27.84000002 20.36571469-48.20571469t48.2057147-20.36571466l222.85714313 0q28.38857157 0 62.6742853 14.19428529t54.65142842 34.55999999l383.04000001 382.49142843q19.81714313 20.9142853 19.81714314 48.75428532zM1060.74751475 580.57142843q0 28.38857157-19.81714313 48.2057147l-263.04 263.58857157q-20.9142853 19.81714313-48.75428531 19.81714312-19.26857155 0-31.61142843-7.47428531t-28.38857159-24.13714314l251.79428534-251.7942853q19.81714313-19.81714313 19.81714308-48.20571469 0-27.84000002-19.81714308-48.75428531l-383.04000001-382.49142845q-20.36571468-20.36571468-54.65142842-34.55999999t-62.67428532-14.19428534l120 0q28.38857157 0 62.67428532 14.19428534t54.65142842 34.55999999l383.03999998 382.49142845q19.81714313 20.9142853 19.81714314 48.75428531z" fill="currentColor"></path>
</svg>
        40
      </div>
    </div>
  </div>
</section>
      
      
      
      
<section class="widget-toc widget-item layout-margin content-padding--primary soft-size--large soft-style--box">
  <div class="widget-title">
    <svg class="icon icon-toc" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <path d="M134.50666666 767.46666668H460.8c27.73333333 0 50.24000001 22.50666668 50.24000001 50.23999999v50.13333333c0 27.73333333-22.50666668 50.24000001-50.24000001 50.24000001H134.50666666c-27.73333333 0-50.24000001-22.50666668-50.23999999-50.24000001v-50.13333333c0.10666668-27.73333333 22.50666668-50.24000001 50.24000001-50.24000001zM84.37333332 541.65333333h326.18666669c27.73333333 0 50.24000001 22.39999999 50.23999999 50.13333334v50.24000001c0 27.73333333-22.50666668 50.24000001-50.24000002 50.23999999H84.37333332c-27.73333333 0-50.24000001-22.50666668-50.23999999-50.23999999v-50.24000001c0-27.73333333 22.50666668-50.13333334 50.24000001-50.13333334zM134.50666666 315.83999999H460.8c27.73333333 0 50.24000001 22.50666668 50.24000001 50.24000001v50.24000001c0 27.73333333-22.50666668 50.13333334-50.24000001 50.13333333H134.50666666c-27.73333333 0-50.24000001-22.39999999-50.23999999-50.13333333v-50.24000001c0.10666668-27.84000001 22.50666668-50.24000001 50.24000001-50.23999999zM209.81333332 89.91999999h326.18666671c27.73333333 0 50.24000001 22.39999999 50.23999997 50.13333335v50.23999999c0 27.73333333-22.50666668 50.24000001-50.24000001 50.24000001H209.81333332c-27.73333333 0-50.24000001-22.50666668-50.23999999-50.24000001v-50.24000001c0-27.73333333 22.50666668-50.13333334 50.24000001-50.13333333zM692.05333333 623.36l274.66666669 176.00000002c23.36000001 14.93333333 30.08 45.97333334 15.14666666 69.33333332L954.77333334 910.93333333c-14.93333333 23.25333334-45.97333334 30.08-69.33333335 15.14666667l-274.66666666-176c-23.36000001-14.93333333-30.08-45.97333334-15.14666667-69.33333333l27.09333334-42.24000001c14.93333333-23.36000001 46.08000001-30.08 69.33333333-15.14666666z" fill="currentColor"></path>
</svg>
    <span>TOC</span>
  </div>
  <div class="widget-body">
    <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%88%9B%E5%BB%BA%E6%A8%A1%E5%BC%8F"><span class="toc-number">1.</span> <span class="toc-text">创建模式</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F"><span class="toc-number">1.1.</span> <span class="toc-text">工厂模式</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E7%AE%80%E5%8D%95%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F"><span class="toc-number">1.1.1.</span> <span class="toc-text">简单工厂模式</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%B7%A5%E5%8E%82%E6%96%B9%E6%B3%95%E6%A8%A1%E5%BC%8F"><span class="toc-number">1.1.2.</span> <span class="toc-text">工厂方法模式</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%8A%BD%E8%B1%A1%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F"><span class="toc-number">1.1.3.</span> <span class="toc-text">抽象工厂模式</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F%E9%80%82%E7%94%A8%E7%9A%84%E5%9C%BA%E5%90%88"><span class="toc-number">1.1.4.</span> <span class="toc-text">工厂模式适用的场合</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%B8%89%E7%A7%8D%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F%E7%9A%84%E4%BD%BF%E7%94%A8%E9%80%89%E6%8B%A9"><span class="toc-number">1.1.5.</span> <span class="toc-text">三种工厂模式的使用选择</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F"><span class="toc-number">1.2.</span> <span class="toc-text">单例模式</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E9%A5%BF%E6%B1%89%E5%BC%8F"><span class="toc-number">1.2.1.</span> <span class="toc-text">饿汉式</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%87%92%E6%B1%89%E5%BC%8F"><span class="toc-number">1.2.2.</span> <span class="toc-text">懒汉式</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F%E5%92%8C%E7%BA%BF%E7%A8%8B%E5%AE%89%E5%85%A8"><span class="toc-number">1.2.3.</span> <span class="toc-text">单例模式和线程安全</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%BF%9D%E8%AF%81%E6%87%92%E5%8A%A0%E8%BD%BD%E7%9A%84%E7%BA%BF%E7%A8%8B%E5%AE%89%E5%85%A8"><span class="toc-number">1.2.4.</span> <span class="toc-text">保证懒加载的线程安全</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%BD%93%E7%84%B6%E8%BF%98%E6%98%AF%E9%9D%99%E6%80%81%E5%86%85%E9%83%A8%E7%B1%BB"><span class="toc-number">1.2.5.</span> <span class="toc-text">当然还是静态内部类</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%9E%9A%E4%B8%BE-%E9%BB%98%E8%AE%A4%E5%B0%B1%E6%98%AF%E5%8D%95%E4%BE%8B%E7%9A%84%E7%BA%BF%E7%A8%8B%E5%AE%89%E5%85%A8%E7%9A%84"><span class="toc-number">1.2.6.</span> <span class="toc-text">枚举,默认就是单例的线程安全的</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%BB%BA%E9%80%A0%E8%80%85%E6%A8%A1%E5%BC%8F"><span class="toc-number">1.3.</span> <span class="toc-text">建造者模式</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%A8%A1%E5%BC%8F%E7%9A%84%E7%BB%93%E6%9E%84%E5%92%8C%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="toc-number">1.3.1.</span> <span class="toc-text">模式的结构和代码示例</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%BB%BA%E9%80%A0%E8%80%85%E6%A8%A1%E5%BC%8F%E7%9A%84%E4%BC%98%E7%BC%BA%E7%82%B9"><span class="toc-number">1.3.2.</span> <span class="toc-text">建造者模式的优缺点</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%BB%BA%E9%80%A0%E8%80%85%E6%A8%A1%E5%BC%8F%E4%B8%8E%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F%E7%9A%84%E4%B8%8D%E5%90%8C"><span class="toc-number">1.3.3.</span> <span class="toc-text">建造者模式与工厂模式的不同</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%8E%9F%E5%9E%8B%E6%A8%A1%E5%BC%8F"><span class="toc-number">1.4.</span> <span class="toc-text">原型模式</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%B7%B1%E6%8B%B7%E8%B4%9D%E5%92%8C%E6%B5%85%E6%8B%B7%E8%B4%9D"><span class="toc-number">1.4.1.</span> <span class="toc-text">深拷贝和浅拷贝</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%8E%9F%E5%9E%8B%E6%A8%A1%E5%BC%8F%E7%9A%84%E7%BB%93%E6%9E%84%E5%92%8C%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="toc-number">1.4.2.</span> <span class="toc-text">原型模式的结构和代码示例</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%BB%93%E6%9E%84%E6%A8%A1%E5%BC%8F"><span class="toc-number">2.</span> <span class="toc-text">结构模式</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%80%82%E9%85%8D%E5%99%A8%E6%A8%A1%E5%BC%8F"><span class="toc-number">2.1.</span> <span class="toc-text">适配器模式</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E7%B1%BB%E7%9A%84%E9%80%82%E9%85%8D%E5%99%A8%E6%A8%A1%E5%BC%8F"><span class="toc-number">2.1.1.</span> <span class="toc-text">类的适配器模式</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%AF%B9%E8%B1%A1%E7%9A%84%E9%80%82%E9%85%8D%E5%99%A8%E6%A8%A1%E5%BC%8F"><span class="toc-number">2.1.2.</span> <span class="toc-text">对象的适配器模式</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%8E%A5%E5%8F%A3%E7%9A%84%E9%80%82%E9%85%8D%E5%99%A8%E6%A8%A1%E5%BC%8F"><span class="toc-number">2.1.3.</span> <span class="toc-text">接口的适配器模式</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%A3%85%E9%A5%B0%E5%99%A8%E6%A8%A1%E5%BC%8F"><span class="toc-number">2.2.</span> <span class="toc-text">装饰器模式</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E8%A3%85%E9%A5%B0%E8%80%85%E6%A8%A1%E5%BC%8F%E7%BB%93%E6%9E%84%E5%9B%BE%E4%B8%8E%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="toc-number">2.2.1.</span> <span class="toc-text">装饰者模式结构图与代码示例</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BB%A3%E7%90%86%E6%A8%A1%E5%BC%8F"><span class="toc-number">2.3.</span> <span class="toc-text">代理模式</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E7%94%A8%E4%BB%A3%E7%90%86%E6%A8%A1%E5%BC%8F%EF%BC%9F"><span class="toc-number">2.3.1.</span> <span class="toc-text">为什么要用代理模式？</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E9%9D%99%E6%80%81%E4%BB%A3%E7%90%86"><span class="toc-number">2.3.2.</span> <span class="toc-text">静态代理</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86"><span class="toc-number">2.3.3.</span> <span class="toc-text">动态代理</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#CGLIB%E4%BB%A3%E7%90%86"><span class="toc-number">2.3.4.</span> <span class="toc-text">CGLIB代理</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%A4%96%E8%A7%82%E6%A8%A1%E5%BC%8F"><span class="toc-number">2.4.</span> <span class="toc-text">外观模式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%A1%A5%E6%8E%A5%E6%A8%A1%E5%BC%8F"><span class="toc-number">2.5.</span> <span class="toc-text">桥接模式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%BB%84%E5%90%88%E6%A8%A1%E5%BC%8F"><span class="toc-number">2.6.</span> <span class="toc-text">组合模式</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%A8%A1%E5%BC%8F%E7%BB%93%E6%9E%84%E5%92%8C%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="toc-number">2.6.1.</span> <span class="toc-text">模式结构和代码示例</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BA%AB%E5%85%83%E6%A8%A1%E5%BC%8F"><span class="toc-number">2.7.</span> <span class="toc-text">享元模式</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%BA%AB%E5%85%83%E6%A8%A1%E5%BC%8F%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="toc-number">2.7.1.</span> <span class="toc-text">享元模式代码示例</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%85%B3%E7%B3%BB%E6%A8%A1%E5%BC%8F"><span class="toc-number">3.</span> <span class="toc-text">关系模式</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%AD%96%E7%95%A5%E6%A8%A1%E5%BC%8F"><span class="toc-number">3.1.</span> <span class="toc-text">策略模式</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E7%AD%96%E7%95%A5%E6%A8%A1%E5%BC%8F%E7%BB%93%E6%9E%84%E5%92%8C%E7%A4%BA%E4%BE%8B%E4%BB%A3%E7%A0%81"><span class="toc-number">3.1.1.</span> <span class="toc-text">策略模式结构和示例代码</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%A8%A1%E6%9D%BF%E6%A8%A1%E5%BC%8F"><span class="toc-number">3.2.</span> <span class="toc-text">模板模式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%A7%82%E5%AF%9F%E8%80%85%E6%A8%A1%E5%BC%8F"><span class="toc-number">3.3.</span> <span class="toc-text">观察者模式</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%A8%A1%E5%BC%8F%E7%BB%93%E6%9E%84%E5%9B%BE%E5%92%8C%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="toc-number">3.3.1.</span> <span class="toc-text">模式结构图和代码示例</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%BF%AD%E4%BB%A3%E5%99%A8%E6%A8%A1%E5%BC%8F"><span class="toc-number">3.4.</span> <span class="toc-text">迭代器模式</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E8%BF%AD%E4%BB%A3%E5%99%A8%E6%A8%A1%E5%BC%8F%E7%BB%93%E6%9E%84%E5%92%8C%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="toc-number">3.4.1.</span> <span class="toc-text">迭代器模式结构和代码示例</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%B4%A3%E4%BB%BB%E9%93%BE%E6%A8%A1%E5%BC%8F"><span class="toc-number">3.5.</span> <span class="toc-text">责任链模式</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E8%B4%A3%E4%BB%BB%E9%93%BE%E6%A8%A1%E5%BC%8F%E7%9A%84%E7%BB%93%E6%9E%84%E5%92%8C%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="toc-number">3.5.1.</span> <span class="toc-text">责任链模式的结构和代码示例</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%91%BD%E4%BB%A4%E6%A8%A1%E5%BC%8F"><span class="toc-number">3.6.</span> <span class="toc-text">命令模式</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%91%BD%E4%BB%A4%E6%A8%A1%E5%BC%8F%E7%BB%93%E6%9E%84%E5%92%8C%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="toc-number">3.6.1.</span> <span class="toc-text">命令模式结构和代码示例</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%8A%B6%E6%80%81%E6%A8%A1%E5%BC%8F"><span class="toc-number">3.7.</span> <span class="toc-text">状态模式</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E7%8A%B6%E6%80%81%E6%A8%A1%E5%BC%8F%E7%BB%93%E6%9E%84%E5%92%8C%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="toc-number">3.7.1.</span> <span class="toc-text">状态模式结构和代码示例</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%A4%87%E5%BF%98%E5%BD%95%E6%A8%A1%E5%BC%8F"><span class="toc-number">3.8.</span> <span class="toc-text">备忘录模式</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%A4%87%E5%BF%98%E5%BD%95%E6%A8%A1%E5%BC%8F%E7%BB%93%E6%9E%84%E5%9B%BE%E5%92%8C%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="toc-number">3.8.1.</span> <span class="toc-text">备忘录模式结构图和代码示例</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%AE%BF%E9%97%AE%E8%80%85%E6%A8%A1%E5%BC%8F"><span class="toc-number">3.9.</span> <span class="toc-text">访问者模式</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E8%AE%BF%E9%97%AE%E8%80%85%E6%A8%A1%E5%BC%8F%E7%BB%93%E6%9E%84%E5%92%8C%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="toc-number">3.9.1.</span> <span class="toc-text">访问者模式结构和代码示例</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%B8%AD%E4%BB%8B%E8%80%85%E6%A8%A1%E5%BC%8F"><span class="toc-number">3.10.</span> <span class="toc-text">中介者模式</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%A8%A1%E4%B8%AD%E4%BB%8B%E8%80%85%E5%BC%8F%E7%BB%93%E6%9E%84%E5%92%8C%E4%BB%A3%E7%A0%81%E7%A4%BA%E4%BE%8B"><span class="toc-number">3.10.1.</span> <span class="toc-text">模中介者式结构和代码示例</span></a></li></ol></li></ol></li></ol>
  </div>
</section>

    </div>
  
    <div class="article-info">
      
      
      
      
      <section id="blog-content" class="article-entry markdown-body layout-margin content-padding--large soft-size--large soft-style--box">
        <blockquote>
<p>设计模式分为三大类:</p>
<ul>
<li>创建型（五种）： 工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式</li>
<li>结构型模式（七种）: 适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式</li>
<li>行为型模式（十一种）：策略模式、模版方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式</li>
</ul>
</blockquote>
<h2 id="创建模式"><a href="#创建模式" class="headerlink" title="创建模式"></a>创建模式</h2><h3 id="工厂模式"><a href="#工厂模式" class="headerlink" title="工厂模式"></a>工厂模式</h3><h4 id="简单工厂模式"><a href="#简单工厂模式" class="headerlink" title="简单工厂模式"></a>简单工厂模式</h4><blockquote>
<p>定义了一个创建对象的类，由这个类来封装实例化对象的行为。</p>
</blockquote>
<p><strong>举例：</strong>（我们举一个<code>pizza</code>工厂的例子）</p>
<p>pizza工厂一共生产三种类型的<code>pizza</code>：<code>chesse</code>、<code>pepper</code>、<code>greak</code>。通过工厂类（<code>SimplePizzaFactory</code>）实例化这三种类型的对象。</p>
<pre><code class="prettyprint">public class SimplePizzaFactory &#123;
    public Pizza CreatePizza(String ordertype) &#123;
        Pizza pizza = null;
        if (ordertype.equals(&quot;cheese&quot;)) &#123;
            pizza = new CheesePizza();
        &#125; else if (ordertype.equals(&quot;greek&quot;)) &#123;
            pizza = new GreekPizza();
        &#125; else if (ordertype.equals(&quot;pepper&quot;)) &#123;
            pizza = new PepperPizza();
        &#125;
        return pizza;
    &#125;
&#125;

interface Pizza &#123;
    void prepare();
&#125;

class CheesePizza implements Pizza &#123;

    @Override
    public void prepare() &#123;

    &#125;
&#125;

class GreekPizza implements Pizza &#123;

    @Override
    public void prepare() &#123;

    &#125;
&#125;

class PepperPizza implements Pizza &#123;

    @Override
    public void prepare() &#123;

    &#125;
&#125;
</code></pre>
<p>简单工厂存在的问题与解决方法： 简单工厂模式有一个问题就是，类的创建依赖工厂类，也就是说，如果想要拓展程序，必须对工厂类进行修改，这违背了开闭原则，所以，从设计角度考虑，有一定的问题，如何解决？我们可以定义一个创建对象的抽象方法并创建多个不同的工厂类实现该抽象方法，这样一旦需要增加新的功能，直接增加新的工厂类就可以了，不需要修改之前的代码。这种方法也就是我们接下来要说的工厂方法模式。</p>
<h4 id="工厂方法模式"><a href="#工厂方法模式" class="headerlink" title="工厂方法模式"></a>工厂方法模式</h4><blockquote>
<p> 定义了一个创建对象的抽象方法，由子类决定要实例化的类。工厂方法模式将对象的实例化推迟到子类。</p>
</blockquote>
<p><strong>举例：</strong>（我们依然举<code>pizza</code>工厂的例子，不过这个例子中，<code>pizza</code>产地有两个：伦敦和纽约）。添加了一个新的产地，如果用简单工厂模式的的话，我们要去修改工厂代码，并且会增加一堆的if else语句。而工厂方法模式克服了简单工厂要修改代码的缺点，它会直接创建两个工厂，纽约工厂和伦敦工厂。</p>
<pre><code class="prettyprint">public abstract class OrderPizza &#123;
    abstract Pizza createPizza(String orderType);
&#125;
</code></pre>
<p>两个工厂类继承<code>OrderPizza</code>并实现抽象方法：</p>
<pre><code class="prettyprint">public class LDOrderPizza extends OrderPizza &#123;
    @Override
    Pizza createPizza(String orderType) &#123;
        Pizza pizza = null;
        if (orderType.equals(&quot;cheese&quot;)) &#123;
            pizza = new LDCheesePizza();
        &#125; else if (orderType.equals(&quot;pepper&quot;)) &#123;
            pizza = new LDPepperPizza();
        &#125;
        return pizza;
    &#125;
&#125;
/************************************************/
public class NYOrderPizza extends OrderPizza &#123;

    Pizza createPizza(String orderType) &#123;
        Pizza pizza = null;
        if (orderType.equals(&quot;cheese&quot;)) &#123;
            pizza = new NYCheesePizza();
        &#125; else if (orderType.equals(&quot;pepper&quot;)) &#123;
            pizza = new NYPepperPizza();
        &#125;
        return pizza;

    &#125;

&#125;
</code></pre>
<p><strong>工厂方法存在的问题与解决方法：</strong>客户端需要创建类的具体的实例。简单来说就是用户要订纽约工厂的披萨，他必须去纽约工厂，想订伦敦工厂的披萨，必须去伦敦工厂。 当伦敦工厂和纽约工厂发生变化了，用户也要跟着变化，这无疑就增加了用户的操作复杂性。为了解决这一问题，我们可以把工厂类抽象为接口，用户只需要去找默认的工厂提出自己的需求（传入参数），便能得到自己想要产品，而不用根据产品去寻找不同的工厂，方便用户操作。这也就是我们接下来要说的抽象工厂模式。</p>
<h4 id="抽象工厂模式"><a href="#抽象工厂模式" class="headerlink" title="抽象工厂模式"></a>抽象工厂模式</h4><blockquote>
<p>定义了一个接口用于创建相关或有依赖关系的对象族，而无需明确指定具体类。</p>
</blockquote>
<p><strong>举例：</strong>（我们依然举<code>pizza</code>工厂的例子，<code>pizza</code>工厂有两个：纽约工厂和伦敦工厂）。</p>
<p>工厂接口：</p>
<pre><code class="prettyprint">public interface AbsFactory &#123;
       Pizza CreatePizza(String ordertype) ;
&#125;
</code></pre>
<p>工厂的具体实现：</p>
<pre><code class="prettyprint">public class LDFactory implements AbsFactory &#123;
       @Override
       public Pizza CreatePizza(String ordertype) &#123;
              Pizza pizza = null;
              if (&quot;cheese&quot;.equals(ordertype)) &#123;
                     pizza = new LDCheesePizza();
              &#125; else if (&quot;pepper&quot;.equals(ordertype)) &#123;
                     pizza = new LDPepperPizza();
              &#125;
              return pizza;
       &#125;
&#125;
</code></pre>
<p><code>PizzaStroe</code>的代码如下:</p>
<pre><code class="prettyprint">public class PizzaStroe &#123;
       public static void main(String[] args) &#123;
              OrderPizza mOrderPizza;
              mOrderPizza = new OrderPizza(&quot;London&quot;);
       &#125;
&#125;
</code></pre>
<p>解决了工厂方法模式的问题：在抽象工厂中<code>PizzaStroe</code>中只需要传入参数就可以实例化对象。</p>
<h4 id="工厂模式适用的场合"><a href="#工厂模式适用的场合" class="headerlink" title="工厂模式适用的场合"></a>工厂模式适用的场合</h4><p>大量的产品需要创建，并且这些产品具有共同的接口 </p>
<h4 id="三种工厂模式的使用选择"><a href="#三种工厂模式的使用选择" class="headerlink" title="三种工厂模式的使用选择"></a>三种工厂模式的使用选择</h4><ul>
<li><p><strong>简单工厂 ：</strong> 用来生产同一等级结构中的任意产品。（不支持拓展增加产品）</p>
</li>
<li><p><strong>工厂方法 ：</strong>用来生产同一等级结构中的固定产品。（支持拓展增加产品）</p>
</li>
<li><p><strong>抽象工厂 ：</strong>用来生产不同产品族的全部产品。（支持拓展增加产品；支持增加产品族）</p>
</li>
</ul>
<h3 id="单例模式"><a href="#单例模式" class="headerlink" title="单例模式"></a>单例模式</h3><blockquote>
<p><strong>定义：</strong>确保一个类最多只有一个实例，并提供一个全局访问点</p>
<p>单例模式分为懒汉式（懒加载）和饿汉式（预加载）</p>
</blockquote>
<h4 id="饿汉式"><a href="#饿汉式" class="headerlink" title="饿汉式"></a>饿汉式</h4><blockquote>
<p>预先加载。再进一步解释就是还没有使用该单例对象，但是，该单例对象就已经被加载到内存了。</p>
</blockquote>
<pre><code class="prettyprint">public class PreloadSingleton &#123;
       
       public static PreloadSingleton instance = new PreloadSingleton();
   
       //其他的类无法实例化单例类的对象
       private PreloadSingleton() &#123;
       &#125;;
       
       public static PreloadSingleton getInstance() &#123;
              return instance;
       &#125;
&#125;
</code></pre>
<h4 id="懒汉式"><a href="#懒汉式" class="headerlink" title="懒汉式"></a>懒汉式</h4><blockquote>
<p>为了避免内存的浪费，我们可以采用懒加载，即用到该单例对象的时候再创建。</p>
</blockquote>
<pre><code class="prettyprint">public class Singleton &#123;
       
       private static Singleton instance=null;
       
       private Singleton()&#123;
       &#125;;
       
       public static Singleton getInstance()
       &#123;
              if(instance==null)
              &#123;
                     instance=new Singleton();
              &#125;
              return instance;
              
       &#125;
&#125;
</code></pre>
<h4 id="单例模式和线程安全"><a href="#单例模式和线程安全" class="headerlink" title="单例模式和线程安全"></a>单例模式和线程安全</h4><ul>
<li><p>预加载只有一条语句<code>return instance</code>,这显然可以保证线程安全。但是，我们知道预加载会造成内存的浪费。</p>
</li>
<li><p>懒加载不浪费内存，但是无法保证线程的安全。首先，if判断以及其内存执行代码是非原子性的。其次，<code>new Singleton()</code>无法保证执行的顺序性。</p>
<ul>
<li><p>不满足原子性或者顺序性，线程肯定是不安全的。为什么new Singleton()无法保证顺序性。我们知道创建一个对象分三步:</p>
<pre><code class="prettyprint">memory=allocate();//1:初始化内存空
ctorInstance(memory);//2:初始化对象
instance=memory();//3:设置instance指向刚分配的内存地址
</code></pre>
<p>jvm为了提高程序执行性能，会对没有依赖关系的代码进行重排序，上面2和3行代码可能被重新排序。我们用两个线程来说明线程是不安全的。线程A和线程B都创建对象。其中，A2和A3的重排序，将导致线程B在B1处判断出instance不为空，线程B接下来将访问instance引用的对象。此时，线程B将会访问到一个还未初始化的对象（线程不安全）。</p>
</li>
</ul>
</li>
</ul>
<h4 id="保证懒加载的线程安全"><a href="#保证懒加载的线程安全" class="headerlink" title="保证懒加载的线程安全"></a>保证懒加载的线程安全</h4><p>我们首先想到的就是使用<code>synchronized</code>关键字。<code>synchronized</code>加载<code>getInstace()</code>函数上确实保证了线程的安全。但是，如果要经常的调用<code>getInstance()</code>方法，不管有没有初始化实例，都会唤醒和阻塞线程。为了避免线程的上下文切换消耗大量时间，如果对象已经实例化了，我们没有必要再使用<code>synchronized</code>加锁，直接返回对象。</p>
<pre><code class="prettyprint">public class Singleton &#123;
       private static Singleton instance = null;
       private Singleton() &#123;
       &#125;;
       public static synchronized Singleton getInstance() &#123;
              if (instance == null) &#123;
                     instance = new Singleton();
              &#125;
              return instance;
       &#125;
&#125;
</code></pre>
<p>我们把<code>sychronized</code>加在if(instance&#x3D;&#x3D;null)判断语句里面，<strong>保证instance未实例化的时候才加锁</strong></p>
<pre><code class="prettyprint">public class Singleton &#123;
       private static Singleton instance = null;
       private Singleton() &#123;
       &#125;;
       public static synchronized Singleton getInstance() &#123;
              if (instance == null) &#123;
                     synchronized (Singleton.class) &#123;
                           if (instance == null) &#123;
                                  instance = new Singleton();
                           &#125;
                     &#125;
              &#125;
              return instance;
       &#125;
&#125;
</code></pre>
<p>我们经过前面的讨论知道new一个对象的代码是无法保证顺序性的，因此，我们需要使用另一个关键字<code>volatile</code>保证对象实例化过程的顺序性。<strong>双重校验锁</strong></p>
<pre><code class="prettyprint">public class Singleton &#123;
       private static volatile Singleton instance = null;
       private Singleton() &#123;
       &#125;;
       public static synchronized Singleton getInstance() &#123;
              if (instance == null) &#123;
                     synchronized (instance) &#123;
                           if (instance == null) &#123;
                                  instance = new Singleton();
                           &#125;
                     &#125;
              &#125;
              return instance;
       &#125;
&#125;
</code></pre>
<h4 id="当然还是静态内部类"><a href="#当然还是静态内部类" class="headerlink" title="当然还是静态内部类"></a>当然还是静态内部类</h4><pre><code class="prettyprint">public class Singleton &#123;  
    private static class SingletonHolder &#123;  
    private static final Singleton INSTANCE = new Singleton();  
    &#125;  
    private Singleton ()&#123;&#125;  
    public static final Singleton getInstance() &#123;  
        return SingletonHolder.INSTANCE;  
    &#125;  
&#125;
</code></pre>
<h4 id="枚举-默认就是单例的线程安全的"><a href="#枚举-默认就是单例的线程安全的" class="headerlink" title="枚举,默认就是单例的线程安全的"></a>枚举,默认就是单例的线程安全的</h4><pre><code class="prettyprint">public enum Singleton &#123;  
    INSTANCE;  
    public void whateverMethod() &#123;  
    &#125;  
&#125;
</code></pre>
<h3 id="建造者模式"><a href="#建造者模式" class="headerlink" title="建造者模式"></a>建造者模式</h3><blockquote>
<p><strong>定义：</strong>封装一个复杂对象构造过程，并允许按步骤构造。</p>
<p><strong>定义解释：</strong> 我们可以将建造者模式理解为，假设我们有一个对象需要建立，这个对象是由多个组件（<code>Component</code>）组合而成，每个组件的建立都比较复杂，但运用组件来建立所需的对象非常简单，所以我们就可以将构建复杂组件的步骤与运用组件构建对象分离，使用<code>builder</code>模式可以建立。</p>
</blockquote>
<h4 id="模式的结构和代码示例"><a href="#模式的结构和代码示例" class="headerlink" title="模式的结构和代码示例"></a>模式的结构和代码示例</h4><p>建造者模式结构中包括四种角色：</p>
<ul>
<li>产品(<code>Product</code>)：具体生产器要构造的复杂对象；</li>
<li>抽象建造者(<code>Bulider</code>)：抽象建造者是一个接口，该接口除了为创建一个<code>Product</code>对象的各个组件定义了若干个方法之外，还要定义返回Product对象的方法（定义构造步骤）；</li>
<li>具体生产器(<code>ConcreteBuilder</code>)：实现<code>Builder</code>接口的类，具体建造者将实现<code>Builder</code>接口所定义的方法（生产各个组件）；</li>
<li>指挥者(<code>Director</code>)：指挥者是一个类，该类需要含有<code>Builder</code>接口声明的变量。指挥者的职责是负责向用户提供具体建造者，即指挥者将请求具体建造者类来构造用户所需要的<code>Product</code>对象，如果所请求的具体建造者成功地构造出<code>Product</code>对象，指挥者就可以让该具体生产器返回所构造的<code>Product</code>对象。（按照步骤组装部件，并返回<code>Product</code>）</li>
</ul>
<p><strong>举例：</strong>我们如果构建生成一台电脑，那么我们可能需要这么几个步骤（1）需要一个主机（2）需要一个显示器（3）需要一个键盘（4）需要一个鼠标。虽然我们具体在构建一台主机的时候，每个对象的实际步骤是不一样的，比如，有的对象构建了i7cpu的主机，有的对象构建了i5cpu的主机，有的对象构建了普通键盘，有的对象构建了机械键盘等。但不管怎样，你总是需要经过一个步骤就是构建一台主机，一台键盘。对于这个例子，我们就可以使用建造者模式来生成一台电脑，他需要通过多个步骤来生成。</p>
<p><code>ComputerBuilder</code>类定义构造步骤：</p>
<pre><code class="prettyprint">public abstract class ComputerBuilder &#123;
   
    protected Computer computer;
   
    public Computer getComputer() &#123;
        return computer;
    &#125;
   
    public void buildComputer() &#123;
        computer = new Computer();
        System.out.println(&quot;生成了一台电脑！！！&quot;);
    &#125;
    public abstract void buildMaster();
    public abstract void buildScreen();
    public abstract void buildKeyboard();
    public abstract void buildMouse();
    public abstract void buildAudio();
&#125;
</code></pre>
<p><code>HPComputerBuilder</code>定义各个组件：</p>
<pre><code class="prettyprint">public class HPComputerBuilder extends ComputerBuilder &#123;
    @Override
    public void buildMaster() &#123;
        // TODO Auto-generated method stub
        computer.setMaster(&quot;i7,16g,512SSD,1060&quot;);
        System.out.println(&quot;(i7,16g,512SSD,1060)的惠普主机&quot;);
    &#125;
    @Override
    public void buildScreen() &#123;
        // TODO Auto-generated method stub
        computer.setScreen(&quot;1080p&quot;);
        System.out.println(&quot;(1080p)的惠普显示屏&quot;);
    &#125;
    @Override
    public void buildKeyboard() &#123;
        // TODO Auto-generated method stub
        computer.setKeyboard(&quot;cherry 青轴机械键盘&quot;);
        System.out.println(&quot;(cherry 青轴机械键盘)的键盘&quot;);
    &#125;
    @Override
    public void buildMouse() &#123;
        // TODO Auto-generated method stub
        computer.setMouse(&quot;MI 鼠标&quot;);
        System.out.println(&quot;(MI 鼠标)的鼠标&quot;);
    &#125;
    @Override
    public void buildAudio() &#123;
        // TODO Auto-generated method stub
        computer.setAudio(&quot;飞利浦 音响&quot;);
        System.out.println(&quot;(飞利浦 音响)的音响&quot;);
    &#125;
&#125;
</code></pre>
<p><code>Director</code>类对组件进行组装并生成产品</p>
<pre><code class="prettyprint">public class Director &#123;
   
    private ComputerBuilder computerBuilder;
    public void setComputerBuilder(ComputerBuilder computerBuilder) &#123;
        this.computerBuilder = computerBuilder;
    &#125;
   
    public Computer getComputer() &#123;
        return computerBuilder.getComputer();
    &#125;
   
    public void constructComputer() &#123;
        computerBuilder.buildComputer();
        computerBuilder.buildMaster();
        computerBuilder.buildScreen();
        computerBuilder.buildKeyboard();
        computerBuilder.buildMouse();
        computerBuilder.buildAudio();
    &#125;
&#125;
</code></pre>
<h4 id="建造者模式的优缺点"><a href="#建造者模式的优缺点" class="headerlink" title="建造者模式的优缺点"></a>建造者模式的优缺点</h4><blockquote>
<p>优点：</p>
<ul>
<li>将一个对象分解为各个组件</li>
<li>将对象组件的构造封装起来</li>
<li>可以控制整个对象的生成过程</li>
</ul>
<p>缺点：</p>
<ul>
<li>对不同类型的对象需要实现不同的具体构造器的类，这可能回答大大增加类的数量</li>
</ul>
</blockquote>
<h4 id="建造者模式与工厂模式的不同"><a href="#建造者模式与工厂模式的不同" class="headerlink" title="建造者模式与工厂模式的不同"></a>建造者模式与工厂模式的不同</h4><p>建造者模式构建对象的时候，对象通常构建的过程中需要多个步骤，就像我们例子中的先有主机，再有显示屏，再有鼠标等等，建造者模式的作用就是将这些复杂的构建过程封装起来。工厂模式构建对象的时候通常就只有一个步骤，调用一个工厂方法就可以生成一个对象。</p>
<h3 id="原型模式"><a href="#原型模式" class="headerlink" title="原型模式"></a>原型模式</h3><blockquote>
<p><strong>定义：</strong>通过复制现有实例来创建新的实例，无需知道相应类的信息。</p>
<p>其实就是当需要创建一个指定的对象时，我们刚好有一个这样的对象，但是又不能直接使用，我会clone一个一毛一样的新对象来使用；基本上这就是原型模式。关键字：Clone。</p>
</blockquote>
<h4 id="深拷贝和浅拷贝"><a href="#深拷贝和浅拷贝" class="headerlink" title="深拷贝和浅拷贝"></a>深拷贝和浅拷贝</h4><p><strong>深拷贝：</strong>将一个对象复制后，不论是基本数据类型还有引用类型，都是重新创建的。简单来说，就是深复制进行了完全彻底的复制，而浅复制不彻底。clone明显是深复制，clone出来的对象是是不能去影响原型对象的</p>
<p><strong>浅拷贝：</strong>将一个对象复制后，基本数据类型的变量都会重新创建，而引用类型，指向的还是原对象所指向的</p>
<h4 id="原型模式的结构和代码示例"><a href="#原型模式的结构和代码示例" class="headerlink" title="原型模式的结构和代码示例"></a>原型模式的结构和代码示例</h4><ul>
<li><p><code>Client</code>：使用者</p>
</li>
<li><p><code>Prototype</code>：接口（抽象类），声明具备clone能力，例如java中得Cloneable接口</p>
</li>
<li><p><code>ConcretePrototype</code>：具体的原型类</p>
</li>
</ul>
<p>重点在于<code>Prototype</code>接口和<code>Prototype</code>接口的实现类<code>ConcretePrototype</code>。原型模式的具体实现：一个原型类，只需要实现<code>Cloneable</code>接口，覆写<code>clone</code>方法，此处<code>clone</code>方法可以改成任意的名称，因为<code>Cloneable</code>接口是个空接口，你可以任意定义实现类的方法名，如<code>cloneA</code>或者<code>cloneB</code>，因为此处的重点是<code>super.clone()</code>这句话，<code>super.clone()</code>调用的是<code>Object</code>的<code>clone()</code>方法。</p>
<pre><code class="prettyprint">public class Prototype implements Cloneable &#123;  
     public Object clone() throws CloneNotSupportedException &#123;  
         Prototype proto = (Prototype) super.clone();  
         return proto;  
     &#125;  
&#125;  
</code></pre>
<blockquote>
<p>原型模式的本质就是clone，可以解决构建复杂对象的资源消耗问题，能再某些场景中提升构建对象的效率；还有一个重要的用途就是保护性拷贝，可以通过返回一个拷贝对象的形式，实现只读的限制。</p>
</blockquote>
<h2 id="结构模式"><a href="#结构模式" class="headerlink" title="结构模式"></a>结构模式</h2><h3 id="适配器模式"><a href="#适配器模式" class="headerlink" title="适配器模式"></a>适配器模式</h3><blockquote>
<p><strong>定义：</strong> 适配器模式将某个类的接口转换成客户端期望的另一个接口表示，目的是消除由于接口不匹配所造成的类的兼容性问题。分为类的适配器模式，对象的适配器模式，接口的适配器模式</p>
</blockquote>
<h4 id="类的适配器模式"><a href="#类的适配器模式" class="headerlink" title="类的适配器模式"></a>类的适配器模式</h4><blockquote>
<p>通过多重继承目标接口和被适配者类方式来实现适配。<em>将USB接口转为VGA接口</em></p>
</blockquote>
<p><code>USBImpl</code></p>
<pre><code class="prettyprint">public class USBImpl implements USB&#123;
       @Override
       public void showPPT() &#123;
              System.out.println(&quot;PPT内容演示&quot;);
       &#125;
&#125;
</code></pre>
<p><code>USB2VGAAdapter</code>继承<code>USBImpl</code>获取<code>USB</code>的功能，其次，实现<code>VGA</code>接口，表示该类的类型为<code>VGA</code>。</p>
<pre><code class="prettyprint">public class USB2VGAAdapter extends USBImpl implements VGA &#123;
       @Override
       public void projection() &#123;
              super.showPPT();
       &#125;
&#125;
</code></pre>
<p><code>Projector</code>将<code>USB</code>映射为<code>VGA</code>，只有<code>VGA</code>接口才可以连接上投影仪进行投影</p>
<pre><code class="prettyprint">public class Projector&lt;T&gt; &#123;
       public void projection(T t) &#123;
              if (t instanceof VGA) &#123;
                     System.out.println(&quot;开始投影&quot;);
                     VGA v = (VGA) t;
                     v.projection();
              &#125; else &#123;
                     System.out.println(&quot;接口不匹配，无法投影&quot;);
              &#125;
       &#125;
    // 测试
    public static void main(String[] args)&#123;
        //通过适配器创建一个VGA对象，这个适配器实际是使用的是USB的showPPT（）方法
        VGA a=new USB2VGAAdapter();
        //进行投影
        Projector p1=new Projector();
        p1.projection(a);
    &#125;
&#125;
</code></pre>
<h4 id="对象的适配器模式"><a href="#对象的适配器模式" class="headerlink" title="对象的适配器模式"></a>对象的适配器模式</h4><blockquote>
<p>对象适配器和类适配器使用了不同的方法实现适配，<strong>对象适配器使用组合，类适配器使用继承</strong>。<em>将USB接口转为VGA接口</em></p>
</blockquote>
<pre><code class="prettyprint">public class USB2VGAAdapter implements VGA &#123;
       USB u = new USBImpl();
       @Override
       public void projection() &#123;
              u.showPPT();
       &#125;
&#125;
</code></pre>
<h4 id="接口的适配器模式"><a href="#接口的适配器模式" class="headerlink" title="接口的适配器模式"></a>接口的适配器模式</h4><blockquote>
<p>当不需要全部实现接口提供的方法时，可先设计一个抽象类实现接口，并为该接口中每个方法提供一个默认实现（空方法），那么该抽象类的子类可有选择地覆盖父类的某些方法来实现需求，它适用于一个接口不想使用其所有的方法的情况。<em>将USB接口转为VGA接口，VGA中的b()和c()不会被实现</em></p>
</blockquote>
<pre><code class="prettyprint">public abstract class USB2VGAAdapter implements VGA &#123;
       USB u = new USBImpl();
       @Override
       public void projection() &#123;
              u.showPPT();
       &#125;
       @Override
       public void b() &#123;
       &#125;;
       @Override
       public void c() &#123;
       &#125;;
&#125;
</code></pre>
<p>USB2VGAAdapter实现，不用去实现b()和c()方法。</p>
<pre><code class="prettyprint">public class AdapterUSB2VGAImpl extends AdapterUSB2VGA &#123;
       public void projection() &#123;
              super.projection();
       &#125;
&#125;
</code></pre>
<ul>
<li><strong>类适配器模式：</strong>当希望将一个类转换成满足另一个新接口的类时，可以使用类的适配器模式，创建一个新类，继承原有的类，实现新的接口即可。</li>
<li><strong>对象适配器模式：</strong>当希望将一个对象转换成满足另一个新接口的对象时，可以创建一个Wrapper类，持有原类的一个实例，在Wrapper类的方法中，调用实例的方法就行。</li>
<li><strong>接口适配器模式：</strong>当不希望实现一个接口中所有的方法时，可以创建一个抽象类Wrapper，实现所有方法，我们写别的类的时候，继承抽象类即可。</li>
</ul>
<h3 id="装饰器模式"><a href="#装饰器模式" class="headerlink" title="装饰器模式"></a>装饰器模式</h3><blockquote>
<p><strong>定义：</strong>动态的将新功能附加到对象上。在对象功能扩展方面，它比继承更有弹性。</p>
</blockquote>
<h4 id="装饰者模式结构图与代码示例"><a href="#装饰者模式结构图与代码示例" class="headerlink" title="装饰者模式结构图与代码示例"></a>装饰者模式结构图与代码示例</h4><ul>
<li><code>Component</code>（被装饰对象的基类）</li>
</ul>
<p>定义一个对象接口，可以给这些对象动态地添加职责。</p>
<ul>
<li><code>ConcreteComponent</code>（具体被装饰对象）</li>
</ul>
<p>定义一个对象，可以给这个对象添加一些职责。</p>
<ul>
<li><code>Decorator</code>（装饰者抽象类）</li>
</ul>
<p>维持一个指向Component实例的引用，并定义一个与Component接口一致的接口。</p>
<ul>
<li><code>ConcreteDecorator</code>（具体装饰者）</li>
</ul>
<p>具体的装饰对象，给内部持有的具体被装饰对象，增加具体的职责。</p>
<img src="/2023/02/20/23-zhong-she-ji-mo-shi-xue-xi/image-20230221211208840.png" class="asset-class" title="image-20230221211208840">

<p>被装饰对象和修饰者继承自同一个超类</p>
<pre><code class="prettyprint">public abstract class Drink &#123;
    public String description=&quot;&quot;;
    private float price=0f;;


    public void setDescription(String description)
    &#123;
        this.description=description;
    &#125;

    public String getDescription()
    &#123;
        return description+&quot;-&quot;+this.getPrice();
    &#125;
    public float getPrice()
    &#123;
        return price;
    &#125;
    public void setPrice(float price)
    &#123;
        this.price=price;
    &#125;
    public abstract float cost();

&#125;
</code></pre>
<p>被装饰的对象</p>
<pre><code class="prettyprint">public class Coffee extends Drink &#123;
    @Override
    public float cost() &#123;
        return super.getPrice();
    &#125;

&#125;
</code></pre>
<pre><code class="prettyprint">public class Decaf extends Coffee &#123;
    public Decaf()&#123;
        super();
        this.setPrice(1.5f);
    &#125;
&#125;
</code></pre>
<pre><code class="prettyprint">public class LongBlack extends Coffee &#123;
    public LongBlack()&#123;
        super();
        this.setPrice(1f);
    &#125;
&#125;
</code></pre>
<p>装饰者不仅要考虑自身，还要考虑被它修饰的对象，它是在被修饰的对象上继续添加修饰。例如，咖啡里面加牛奶，再加巧克力。加糖后价格为coffee+milk。再加牛奶价格为coffee+milk+chocolate。</p>
<pre><code class="prettyprint">public class Decorator extends Drink &#123;
    private Drink Obj;
    public Decorator(Drink Obj) &#123;
        this.Obj = Obj;
    &#125;;
    @Override
    public float cost() &#123;
        return super.getPrice() + Obj.cost();
    &#125;
    @Override
    public String getDescription() &#123;
        return super.description + &quot;-&quot; + super.getPrice() + &quot;&amp;&amp;&quot; + Obj.getDescription();
    &#125;
&#125;
</code></pre>
<p>装饰者实例化（加牛奶）</p>
<pre><code class="prettyprint">public class Milk extends Decorator &#123;
    public Milk(Drink Obj) &#123;
        super(Obj);
        super.setDescription(&quot;Milk&quot;);
        super.setPrice(2.0f);
    &#125;
&#125;
</code></pre>
<p>装饰者实例化（加巧克力）</p>
<pre><code class="prettyprint">public class Chocolate extends Decorator &#123;
    public Chocolate(Drink Obj) &#123;
        super(Obj);
        super.setDescription(&quot;Chocolate&quot;);
        super.setPrice(3.0f);
    &#125;
&#125;
</code></pre>
<p>coffee店：初始化一个被修饰对象，修饰者实例需要对被修改者实例化，才能对具体的被修饰者进行修饰</p>
<pre><code class="prettyprint">public class CoffeeBar &#123;
    public static void main(String[] args) &#123;
        Drink order;
        order = new Decaf();
        System.out.println(&quot;order1 price:&quot; + order.cost());
        System.out.println(&quot;order1 desc:&quot; + order.getDescription());
        System.out.println(&quot;****************&quot;);
        order = new LongBlack();
        order = new Milk(order);
        order = new Chocolate(order);
        order = new Chocolate(order);
        System.out.println(&quot;order2 price:&quot; + order.cost());
        System.out.println(&quot;order2 desc:&quot; + order.getDescription());
    &#125;
&#125;
</code></pre>
<blockquote>
<p>装饰者和被装饰者之间必须是一样的类型,也就是要有共同的超类。在这里应用继承并不是实现方法的复制,而是实现类型的匹配。因为装饰者和被装饰者是同一个类型,因此装饰者可以取代被装饰者,这样就使被装饰者拥有了装饰者独有的行为。根据装饰者模式的理念,我们可以在任何时候,实现新的装饰者增加新的行为。如果是用继承,每当需要增加新的行为时,就要修改原程序了。</p>
</blockquote>
<h3 id="代理模式"><a href="#代理模式" class="headerlink" title="代理模式"></a>代理模式</h3><blockquote>
<p><strong>定义：</strong>代理模式给某一个对象提供一个代理对象，并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。</p>
</blockquote>
<h4 id="为什么要用代理模式？"><a href="#为什么要用代理模式？" class="headerlink" title="为什么要用代理模式？"></a>为什么要用代理模式？</h4><p>中介隔离作用：在某些情况下，一个客户类不想或者不能直接引用一个委托对象，而代理类对象可以在客户类和委托对象之间起到中介的作用，其特征是代理类和委托类实现相同的接口。</p>
<p>开闭原则，增加功能：代理类除了是客户类和委托类的中介之外，我们还可以通过给代理类增加额外的功能来扩展委托类的功能，这样做我们只需要修改代理类而不需要再修改委托类，符合代码设计的开闭原则。代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类，以及事后对返回结果的处理等。代理类本身并不真正实现服务，而是同过调用委托类的相关方法，来提供特定的服务。真正的业务功能还是由委托类来实现，但是可以在业务功能执行的前后加入一些公共的服务。例如我们想给项目加入缓存、日志这些功能，我们就可以使用代理类来完成，而没必要打开已经封装好的委托类。</p>
<p>代理模式分为三类：1. 静态代理 2. 动态代理 3. CGLIB代理</p>
<h4 id="静态代理"><a href="#静态代理" class="headerlink" title="静态代理"></a>静态代理</h4><img src="/2023/02/20/23-zhong-she-ji-mo-shi-xue-xi/image-20230221212332891.png" class="asset-class" title="image-20230221212332891">

<ul>
<li><p>创建接口类</p>
<pre><code class="prettyprint">public interface BuyHouse &#123;
    void buyHouse();
&#125;
</code></pre>
</li>
<li><p>实现服务接口</p>
<pre><code class="prettyprint">public class BuyHouseImpl implements BuyHouse &#123;
    @Override
    public void buyHouse() &#123;
        System.out.println(&quot;我要买房&quot;);
    &#125;
&#125;
</code></pre>
</li>
<li><p>创建代理</p>
<pre><code class="prettyprint">public class BuyHouseProxy implements BuyHouse &#123;
    private final BuyHouse buyHouse;
    public BuyHouseProxy(final BuyHouse buyHouse) &#123;
        this.buyHouse = buyHouse;
    &#125;
    @Override
    public void buyHouse() &#123;
        System.out.println(&quot;BuyHouseProxy----买房前准备&quot;);
        buyHouse.buyHouse();
        System.out.println(&quot;BuyHouseProxy---买房后装修&quot;);
    &#125;
&#125;
</code></pre>
</li>
</ul>
<blockquote>
<p><strong>优点：</strong>可以做到在符合开闭原则的情况下对目标对象进行功能扩展。</p>
<p><strong>缺点：</strong> 代理对象与目标对象要实现相同的接口，我们得为每一个服务都得创建代理类，不易管理。同时接口一旦发生改变，代理类也得相应修改。</p>
</blockquote>
<h4 id="动态代理"><a href="#动态代理" class="headerlink" title="动态代理"></a>动态代理</h4><blockquote>
<ul>
<li><p>代理对象,不需要实现接口</p>
</li>
<li><p>代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象(需要我们指定创建代理对象&#x2F;目标对象实现的接口的类型)</p>
</li>
<li><p>代理类不用再实现接口了。但是，要求被代理对象必须有接口。</p>
</li>
</ul>
</blockquote>
<p>动态代理实现：</p>
<p><code>Java.lang.reflect.Proxy</code>类可以直接生成一个代理对象</p>
<p>**Proxy.newProxyInstance(ClassLoader loader, Class&lt;?&gt;[] interfaces, InvocationHandler h) **生成一个代理对象</p>
<ul>
<li>参数1:<code>ClassLoader loader</code> 代理对象的类加载器 一般使用被代理对象的类加载器</li>
<li>参数2:<code>Class&lt;?&gt;[] interfaces</code> 代理对象的要实现的接口 一般使用的被代理对象实现的接口</li>
<li>参数3:<code>InvocationHandler h</code> (接口)执行处理类</li>
</ul>
<p><strong>InvocationHandler中的invoke(Object proxy, Method method, Object[] args)方法：</strong>调用代理类的任何方法，此方法都会执行</p>
<ul>
<li>参数1:代理对象(慎用)</li>
<li>参数2:当前执行的方法</li>
<li>参数3:当前执行的方法运行时传递过来的参数</li>
</ul>
<p><strong>编写动态处理器</strong></p>
<pre><code class="prettyprint">public class DynamicProxyHandler implements InvocationHandler &#123;
    private Object object;
    public DynamicProxyHandler(final Object object) &#123;
        this.object = object;
    &#125;
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable &#123;
        System.out.println(&quot;DynamicProxyHandler---买房前准备&quot;);
        Object result = method.invoke(object, args);
        System.out.println(&quot;DynamicProxyHandler---买房后装修&quot;);
        return result;
    &#125;
&#125;
</code></pre>
<p><strong>测试类</strong></p>
<pre><code class="prettyprint">public class DynamicProxyTest &#123;
    public static void main(String[] args) &#123;
        BuyHouse buyHouse = new BuyHouseImpl();
        BuyHouse proxyBuyHouse = (BuyHouse) Proxy.newProxyInstance(BuyHouse.class.getClassLoader(), new
                Class[]&#123;BuyHouse.class&#125;, new DynamicProxyHandler(buyHouse));
        proxyBuyHouse.buyHouse();
    &#125;
&#125;
</code></pre>
<blockquote>
<p>虽然相对于静态代理，动态代理大大减少了我们的开发任务，同时减少了对业务接口的依赖，降低了耦合度。但是还是有一点点小小的遗憾之处，那就是我们要使用被代理的对象的接口</p>
</blockquote>
<h4 id="CGLIB代理"><a href="#CGLIB代理" class="headerlink" title="CGLIB代理"></a>CGLIB代理</h4><blockquote>
<p>CGLIB 原理：动态生成一个要代理类的子类，子类重写要代理的类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用，顺势织入横切逻辑。它比使用java反射的JDK动态代理要快。</p>
<p>CGLIB 底层：使用字节码处理框架ASM，来转换字节码并生成新的类。不鼓励直接使用ASM，因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。</p>
<p>CGLIB缺点：对于final方法，无法进行代理。</p>
</blockquote>
<p><strong>jar包引入</strong></p>
<pre><code class="prettyprint">&lt;dependency&gt;
    &lt;groupId&gt;cglib&lt;/groupId&gt;
    &lt;artifactId&gt;cglib&lt;/artifactId&gt;
    &lt;version&gt;3.3.0&lt;/version&gt;
&lt;/dependency&gt;
</code></pre>
<p><strong>定义类方法</strong></p>
<pre><code class="prettyprint">public class BuyHouse &#123;
    public void buyHouse(String name)&#123;
        System.out.println(name + &quot;要买房&quot;);
    &#125;
&#125;
</code></pre>
<p><strong>定义拦截器</strong></p>
<pre><code class="prettyprint">public class BuyHouseInterceptor implements MethodInterceptor &#123;

    /**
     * 这里Enhancer类是CGLib中的一个字节码增强器，它可以方便的对你想要处理的类进行扩展，以后会经常看到它。
     * 首先将被代理类TargetObject设置成父类，
     * 然后设置拦截器TargetInterceptor，
     * 最后执行enhancer.create()动态生成一个代理类，并从Object强制转型成父类型TargetObject。
     *
     * @return
     */
    public Object getInstance(Class clazz) &#123;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();
    &#125;

    @Override
    public Object intercept(Object obj, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable &#123;
        System.out.println(&quot;Before invoking buyHouse...&quot;);
        Object result = methodProxy.invokeSuper(obj, objects);
        System.out.println(&quot;After invoking buyHouse...&quot;);
        return result;
    &#125;
&#125;
</code></pre>
<p><strong>参数：</strong><code>Object</code>为由<code>CGLib</code>动态生成的代理类实例，<code>Method</code>为上文中实体类所调用的被代理的方法引用，<code>Object[]</code>为参数值列表，<code>MethodProxy</code>为生成的代理类对方法的代理引用。</p>
<p><strong>返回：</strong>从代理实例的方法调用返回的值。</p>
<p>其中，<code>proxy.invokeSuper(obj,arg) </code>调用代理类实例上的<code>proxy</code>方法的父类方法（即实体类<code>TargetObject</code>中对应的方法）</p>
<p><strong>调用测试</strong></p>
<pre><code class="prettyprint">public class DebuggingCglibDemo &#123;

    public static void main(String[] args) throws Exception &#123;
        String location = DebuggingCglibDemo.class.getResource(&quot;&quot;).getPath().replaceAll(&quot;%20&quot;, &quot; &quot;) + &quot;debugging/&quot;;
        System.out.println(&quot;location -&gt; &quot; + location);
        // 设置 CGLIB 的 debug 输出位置
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, location);
        BuyHouseInterceptor buyHouseInterceptor = new BuyHouseInterceptor();
        BuyHouse buyHouse = (BuyHouse) buyHouseInterceptor.getInstance(BuyHouse.class);
        buyHouse.buyHouse(&quot;roc&quot;);
    &#125;
&#125;
</code></pre>
<blockquote>
<p>CGLIB创建的动态代理对象比JDK创建的动态代理对象的性能更高，但是CGLIB创建代理对象时所花费的时间却比JDK多得多。所以对于单例的对象，因为无需频繁创建对象，用CGLIB合适，反之使用JDK方式要更为合适一些。同时由于CGLib由于是采用动态创建子类的方法，对于final修饰的方法无法进行代理。</p>
</blockquote>
<h3 id="外观模式"><a href="#外观模式" class="headerlink" title="外观模式"></a>外观模式</h3><blockquote>
<p>**定义： **隐藏了系统的复杂性，并向客户端提供了一个可以访问系统的接口。</p>
</blockquote>
<p>该模式就是把一些复杂的流程封装成一个接口供给外部用户更简单的使用。这个模式中，设计到3个角色。</p>
<ul>
<li><p>门面角色：外观模式的核心。它被客户角色调用，它熟悉子系统的功能。内部根据客户角色的需求预定了几种功能的组合。（客户调用，同时自身调用子系统功能）</p>
</li>
<li><p>子系统角色：实现了子系统的功能。它对客户角色和Facade时未知的。它内部可以有系统内的相互交互，也可以由供外界调用的接口。（实现具体功能）</p>
</li>
<li><p>客户角色：通过调用Facede来完成要实现的功能（调用门面角色）。</p>
</li>
</ul>
<p>举例：每个Computer都有CPU、Memory、Disk。在Computer开启和关闭的时候，相应的部件也会开启和关闭</p>
<p><strong>子系统角色</strong></p>
<pre><code class="prettyprint">public class CPU &#123;

    public void start() &#123;
        System.out.println(&quot;cpu is start...&quot;);
    &#125;

    public void shutDown() &#123;
        System.out.println(&quot;CPU is shutDown...&quot;);
    &#125;
&#125;
</code></pre>
<pre><code class="prettyprint">public class Disk &#123;
    public void start() &#123;
        System.out.println(&quot;Disk is start...&quot;);
    &#125;

    public void shutDown() &#123;
        System.out.println(&quot;Disk is shutDown...&quot;);
    &#125;
&#125;
</code></pre>
<pre><code class="prettyprint">public class Memory &#123;
    public void start() &#123;
        System.out.println(&quot;Memory is start...&quot;);
    &#125;

    public void shutDown() &#123;
        System.out.println(&quot;Memory is shutDown...&quot;);
    &#125;
&#125;
</code></pre>
<p><strong>门面角色</strong></p>
<pre><code class="prettyprint">public class Computer &#123;

    private CPU cpu;
    private Memory memory;
    private Disk disk;

    public Computer() &#123;
        cpu = new CPU();
        memory = new Memory();
        disk = new Disk();
    &#125;

    public void start() &#123;
        System.out.println(&quot;Computer start begin&quot;);
        cpu.start();
        disk.start();
        memory.start();
        System.out.println(&quot;Computer start end&quot;);
    &#125;

    public void shutDown() &#123;
        System.out.println(&quot;Computer shutDown begin&quot;);
        cpu.shutDown();
        disk.shutDown();
        memory.shutDown();
        System.out.println(&quot;Computer shutDown end...&quot;);
    &#125;
&#125;
</code></pre>
<p><strong>客户角色</strong></p>
<pre><code class="prettyprint">public class Client &#123;
    public static void main(String[] args) &#123;
        Computer computer = new Computer();
        computer.start();
        System.out.println(&quot;=================&quot;);
        computer.shutDown();
    &#125;
&#125;
</code></pre>
<blockquote>
<p><em>松散耦合</em>：使得客户端和子系统之间解耦，让子系统内部的模块功能更容易扩展和维护；</p>
<p><em>简单易用</em>：客户端根本不需要知道子系统内部的实现，或者根本不需要知道子系统内部的构成，它只需要跟Facade类交互即可。</p>
<p><em>更好的划分访问层次</em>：有些方法是对系统外的，有些方法是系统内部相互交互的使用的。子系统把那些暴露给外部的功能集中到门面中，这样就可以实现客户端的使用，很好的隐藏了子系统内部的细节。</p>
</blockquote>
<h3 id="桥接模式"><a href="#桥接模式" class="headerlink" title="桥接模式"></a>桥接模式</h3><blockquote>
<p><strong>定义：</strong> 将抽象部分与它的实现部分分离，使它们都可以独立地变化。</p>
</blockquote>
<img src="/2023/02/20/23-zhong-she-ji-mo-shi-xue-xi/image-20230221224001605.png" class="asset-class" title="image-20230221224001605">

<ul>
<li><p>创建桥接实现接口</p>
<pre><code class="prettyprint">public interface Software &#123;
    public void run();
&#125;
</code></pre>
</li>
<li><p>创建实现了 <em>Software</em> 接口的实体桥接实现类。</p>
<pre><code class="prettyprint">public class AppStore implements Software &#123;
     
    @Override
    public void run() &#123;
        System.out.println(&quot;run app store&quot;);
    &#125;
&#125;
</code></pre>
<pre><code class="prettyprint">public class Camera implements Software &#123;
     
    @Override
    public void run() &#123;
        System.out.println(&quot;run camera&quot;);
    &#125;
&#125;
</code></pre>
</li>
<li><p>使用 <em>Software</em> 接口创建抽象类 <em>Phone</em>。</p>
<pre><code class="prettyprint">public abstract class Phone &#123;
 
    protected Software software;
 
    public void setSoftware(Software software) &#123;
        this.software = software;
    &#125;
 
    public abstract void run();
 
&#125;
</code></pre>
</li>
<li><p>创建实现了 <em>Phone</em> 抽象类的实体类。</p>
<pre><code class="prettyprint">public class Oppo extends Phone &#123;
    public Oppo(Software software)&#123;
        this.software = software;
    &#125;

    @Override
    public void run() &#123;
        this.software.run();
    &#125;
&#125;
</code></pre>
</li>
<li><p>使用 <em>Phone</em> 和 <em>Software</em> 类运行不同的软件</p>
<pre><code class="prettyprint">public class BridgePatternDemo &#123;
    public static void main(String[] args) &#123;
        Phone oppo1 = new Oppo(new Camera());
        Phone oppo2 = new Oppo(new AppStore());
        oppo1.run();
        oppo2.run();
    &#125;
&#125;
</code></pre>
</li>
</ul>
<blockquote>
<p>从桥接模式的设计上我们可以看出聚合是一种比继承要弱的关联关系，手机类和软件类都可独立的进行变化，不会互相影响</p>
</blockquote>
<h3 id="组合模式"><a href="#组合模式" class="headerlink" title="组合模式"></a>组合模式</h3><blockquote>
<p> <strong>定义：</strong>有时又叫作部分-整体模式，它是一种将对象组合成树状的层次结构的模式，用来表示“部分-整体”的关系，使用户对单个对象和组合对象具有一致的访问性。 </p>
<p> <strong>意图：</strong>将对象组合成树形结构以表示”部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。 </p>
<p> <strong>主要解决：</strong>它在我们树型结构的问题中，模糊了简单元素和复杂元素的概念，客户程序可以像处理简单元素一样来处理复杂元素，从而使得客户程序与复杂元素的内部结构解耦。 </p>
<p> <strong>关键代码：</strong>树枝内部组合该接口，并且含有内部属性 List，里面放 Component。</p>
</blockquote>
<p><strong>优点：</strong></p>
<ul>
<li><p>组合模式使得客户端代码可以一致地处理单个对象和组合对象，无须关心自己处理的是单个对象，还是组合对象，这简化了客户端代码；</p>
</li>
<li><p>更容易在组合体内加入新的对象，客户端不会因为加入了新的对象而更改源代码，满足“开闭原则”；</p>
</li>
</ul>
<p><strong>缺点：</strong></p>
<ul>
<li><p>设计较复杂，客户端需要花更多时间理清类之间的层次关系；</p>
</li>
<li><p>不容易限制容器中的构件；</p>
</li>
<li><p>不容易用继承的方法来增加构件的新功能；</p>
</li>
</ul>
<h4 id="模式结构和代码示例"><a href="#模式结构和代码示例" class="headerlink" title="模式结构和代码示例"></a>模式结构和代码示例</h4><ul>
<li>抽象构件（<code>Component</code>）角色：它的主要作用是为树叶构件和树枝构件声明公共接口，并实现它们的默认行为。在透明式的组合模式中抽象构件还声明访问和管理子类的接口；在安全式的组合模式中不声明访问和管理子类的接口，管理工作由树枝构件完成。</li>
<li>树叶构件（<code>Leaf</code>）角色：是组合中的叶节点对象，它没有子节点，用于实现抽象构件角色中 声明的公共接口。</li>
<li>树枝构件（<code>Composite</code>）角色：是组合中的分支节点对象，它有子节点。它实现了抽象构件角色中声明的接口，它的主要作用是存储和管理子部件，通常包含 <code>Add()</code>、<code>Remove()</code>、<code>GetChild()</code> 等方法</li>
</ul>
<p><strong>举例：</strong>部门人员上下级关系</p>
<ul>
<li><p>组件</p>
<pre><code class="prettyprint">public interface Component &#123;
    public void add(Component c);
    public void remove(Component c);
    public List&lt;Component&gt; getAllChild();
    public void operation();
&#125;
</code></pre>
</li>
<li><p>叶子结点</p>
<pre><code class="prettyprint">public class Employee implements Component &#123;
    private String name;
    private String dept;
    private int salary;
    private List&lt;Component&gt; subordinates;

    //构造函数
    public Employee(String name,String dept, int sal) &#123;
        this.name = name;
        this.dept = dept;
        this.salary = sal;
        subordinates = new ArrayList&lt;Component&gt;();
    &#125;

    @Override
    public String toString()&#123;
        return (&quot;Employee :[ Name : &quot;+ name
                +&quot;, dept : &quot;+ dept + &quot;, salary :&quot;
                + salary+&quot; ]&quot;);
    &#125;

    @Override
    public void add(Component c) &#123;
        subordinates.add(c);
    &#125;

    @Override
    public void remove(Component c) &#123;
        subordinates.remove(c);
    &#125;
    
    @Override
    public List&lt;Component&gt; getAllChild() &#123;
        return subordinates;
    &#125;

    @Override
    public void operation() &#123;
        System.out.println(&quot;Employee :[ Name : &quot;+ name
                +&quot;, dept : &quot;+ dept + &quot;, salary :&quot;
                + salary+&quot; ]&quot;);
    &#125;
&#125;
</code></pre>
</li>
<li><p>测试</p>
<pre><code class="prettyprint">public class CompositePatternDemo &#123;
    public static void main(String[] args) &#123;
        Employee CEO = new Employee(&quot;John&quot;,&quot;CEO&quot;, 30000);

        Employee headSales = new Employee(&quot;Robert&quot;,&quot;Head Sales&quot;, 20000);

        Employee headMarketing = new Employee(&quot;Michel&quot;,&quot;Head Marketing&quot;, 20000);

        Employee clerk1 = new Employee(&quot;Laura&quot;,&quot;Marketing&quot;, 10000);
        Employee clerk2 = new Employee(&quot;Bob&quot;,&quot;Marketing&quot;, 10000);

        Employee salesExecutive1 = new Employee(&quot;Richard&quot;,&quot;Sales&quot;, 10000);
        Employee salesExecutive2 = new Employee(&quot;Rob&quot;,&quot;Sales&quot;, 10000);

        CEO.add(headSales);
        CEO.add(headMarketing);

        headSales.add(salesExecutive1);
        headSales.add(salesExecutive2);

        headMarketing.add(clerk1);
        headMarketing.add(clerk2);

        //打印该组织的所有员工
        CEO.operation();
        for (Component headEmployee : CEO.getAllChild()) &#123;
            headEmployee.operation();
            for (Component employee : headEmployee.getAllChild()) &#123;
                employee.operation();
            &#125;
        &#125;
    &#125;
&#125;
/**
 * Employee :[ Name : John, dept : CEO, salary :30000 ]
 * Employee :[ Name : Robert, dept : Head Sales, salary :20000 ]
 * Employee :[ Name : Richard, dept : Sales, salary :10000 ]
 * Employee :[ Name : Rob, dept : Sales, salary :10000 ]
 * Employee :[ Name : Michel, dept : Head Marketing, salary :20000 ]
 * Employee :[ Name : Laura, dept : Marketing, salary :10000 ]
 * Employee :[ Name : Bob, dept : Marketing, salary :10000 ]
 */
</code></pre>
</li>
</ul>
<h3 id="享元模式"><a href="#享元模式" class="headerlink" title="享元模式"></a>享元模式</h3><blockquote>
<p><strong>定义</strong>：通过共享的方式高效的支持大量细粒度的对象。</p>
<p><strong>主要解决</strong>：在有大量对象时，有可能会造成内存溢出，我们把其中共同的部分抽象出来，如果有相同的业务请求，直接返回在内存中已有的对象，避免重新创建。</p>
<p><strong>关键代码</strong>：用 <code>HashMap </code>存储这些对象</p>
</blockquote>
<p> <strong>何时使用：</strong> </p>
<ul>
<li><p>系统中有大量对象。 </p>
</li>
<li><p>这些对象消耗大量内存。</p>
</li>
<li><p>这些对象的状态大部分可以外部化。 </p>
</li>
<li><p>这些对象可以按照内蕴状态分为很多组，当把外蕴对象从对象中剔除出来时，每一组对象都可以用一个对象来代替。</p>
</li>
<li><p>系统不依赖于这些对象身份，这些对象是不可分辨的。</p>
</li>
</ul>
<p> <strong>应用实例</strong>： 1、JAVA 中的 String，如果有则返回，如果没有则创建一个字符串保存在字符串缓存池里面。 </p>
<p> <strong>优点</strong>：大大减少对象的创建，降低系统的内存，使效率提高。 </p>
<p> <strong>缺点</strong>：提高了系统的复杂度，需要分离出外部状态和内部状态，而且外部状态具有固有化的性质，不应该随着内部状态的变化而变化，否则会造成系统的混乱。 </p>
<h4 id="享元模式代码示例"><a href="#享元模式代码示例" class="headerlink" title="享元模式代码示例"></a>享元模式代码示例</h4><ul>
<li><p><code>Flyweight</code> (享元抽象类)：一般是接口或者抽象类，定义了享元类的公共方法。这些方法可以分享内部状态的数据，也可以调用这些方法修改外部状态。</p>
</li>
<li><p><code>ConcreteFlyweight</code>(具体享元类)：具体享元类实现了抽象享元类的方法，为享元对象开辟了内存空间来保存享元对象的内部数据，同时可以通过和单例模式结合只创建一个享元对象。</p>
</li>
<li><p><code>FlyweightFactory</code>(享元工厂类)：享元工厂类创建并且管理享元类，享元工厂类针对享元类来进行编程，通过提供一个享元池来进行享元对象的管理。一般享元池设计成键值对，或者其他的存储结构来存储。当客户端进行享元对象的请求时，如果享元池中有对应的享元对象则直接返回对应的对象，否则工厂类创建对应的享元对象并保存到享元池。</p>
</li>
</ul>
<ol>
<li><p>创建享元对象接口</p>
<pre><code class="prettyprint">public interface IFlyweight &#123;
    void print();
&#125;
</code></pre>
</li>
<li><p>创建具体享元对象</p>
<pre><code class="prettyprint">public class Flyweight implements IFlyweight &#123;
    private String id;
    public Flyweight(String id)&#123;
        this.id = id;
    &#125;
    @Override
    public void print() &#123;
        System.out.println(&quot;Flyweight.id = &quot; + getId() + &quot; ...&quot;);
    &#125;
    public String getId() &#123;
        return id;
    &#125;
&#125;
</code></pre>
</li>
<li><p>创建工厂，这里要特别注意，为了避免享元对象被重复创建，我们使用HashMap中的key值保证其唯一。</p>
</li>
</ol>
<pre><code class="prettyprint">public class FlyweightFactory &#123;
    private final Map&lt;String, IFlyweight&gt; flyweightMap = new HashMap&lt;&gt;();
    public IFlyweight getFlyweight(String str)&#123;
        IFlyweight flyweight = flyweightMap.get(str);
        if(flyweight == null)&#123;
            flyweight = new Flyweight(str);
            flyweightMap.put(str, flyweight);
        &#125;
        return  flyweight;
    &#125;
    public int getFlyweightMapSize()&#123;
        return flyweightMap.size();
    &#125;
&#125;
</code></pre>
<ol start="4">
<li>测试，我们创建三个字符串，但是只会产生两个享元对象</li>
</ol>
<pre><code class="prettyprint">public class MainTest &#123;
    public static void main(String[] args) &#123;
        FlyweightFactory flyweightFactory = new FlyweightFactory();
        IFlyweight flyweight1 = flyweightFactory.getFlyweight(&quot;A&quot;);
        IFlyweight flyweight2 = flyweightFactory.getFlyweight(&quot;B&quot;);
        IFlyweight flyweight3 = flyweightFactory.getFlyweight(&quot;A&quot;);
        flyweight1.print();
        flyweight2.print();
        flyweight3.print();
        System.out.println(flyweightFactory.getFlyweightMapSize());
    &#125;
&#125;
/**
 * Flyweight.id = A ...
 * Flyweight.id = B ...
 * Flyweight.id = A ...
 * 2
 */
</code></pre>
<h2 id="关系模式"><a href="#关系模式" class="headerlink" title="关系模式"></a>关系模式</h2><h3 id="策略模式"><a href="#策略模式" class="headerlink" title="策略模式"></a>策略模式</h3><blockquote>
<p> <strong>定义：</strong>策略模式定义了一系列算法，并将每个算法封装起来，使他们可以相互替换，且算法的变化不会影响到使用算法的客户。  </p>
<p> <strong>主要解决：</strong>在有多种算法相似的情况下，使用 if…else 所带来的复杂和难以维护。 </p>
<p> <strong>关键代码：</strong>实现同一个接口。</p>
</blockquote>
<p><strong>优点：</strong> </p>
<ul>
<li><p>算法可以自由切换。 </p>
</li>
<li><p>避免使用多重条件判断。 </p>
</li>
<li><p>扩展性良好。</p>
</li>
</ul>
<p><strong>缺点：</strong> </p>
<ul>
<li>策略类会增多。 -</li>
<li>所有策略类都需要对外暴露。</li>
</ul>
<p> <strong>使用场景：</strong> </p>
<ul>
<li><p>如果在一个系统里面有许多类，它们之间的区别仅在于它们的行为，那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。 </p>
</li>
<li><p>一个系统需要动态地在几种算法中选择一种。 </p>
</li>
<li><p>如果一个对象有很多的行为，如果不用恰当的模式，这些行为就只好使用多重的条件选择语句来实现。</p>
</li>
</ul>
<h4 id="策略模式结构和示例代码"><a href="#策略模式结构和示例代码" class="headerlink" title="策略模式结构和示例代码"></a>策略模式结构和示例代码</h4><p><strong>抽象策略角色</strong>： 这个是一个抽象的角色，通常情况下使用接口或者抽象类去实现。对比来说，就是我们的Comparator接口。</p>
<p><strong>具体策略角色</strong>：包装了具体的算法和行为。对比来说，就是实现了Comparator接口的实现一组实现类。</p>
<p><strong>环境角色</strong>：内部会持有一个抽象角色的引用，给客户端调用。</p>
<ul>
<li><p>定义策略接口</p>
<pre><code class="prettyprint">public interface RejectStrategy &#123;
    void reject(String message, Map&lt;String,Object&gt; paramMap, Fix fix);
&#125;
</code></pre>
</li>
<li><p>定义具体策略角色</p>
<pre><code class="prettyprint">@Slf4j
public class AnyMatchStrategy implements RejectStrategy&#123;
    @Override
    public void reject(String message, Map&lt;String, Object&gt; paramMap, Fix fix) &#123;
        Set&lt;String&gt; paramKetSet= paramMap.keySet();
        if(CollectionUtils.intersection(PlaceHolderUtils.keySet(message,fix),paramKetSet).size() &lt;= 0)&#123;
            log.error(&quot;消息占位符替换参数与消息模版完全不匹配，message = &#123;&#125;,param = &#123;&#125;&quot;,message,paramMap);
            throw new RuntimeException(&quot;消息占位符替换参数与消息模版完全不匹配&quot;);
        &#125;
    &#125;
&#125;
</code></pre>
<pre><code class="prettyprint">public class IgnoreRejectStrategy implements RejectStrategy&#123;
    @Override
    public void reject(String message, Map&lt;String, Object&gt; paramMap, Fix fix) &#123;

    &#125;
&#125;
</code></pre>
<pre><code class="prettyprint">@Slf4j
public class TotallyMatchStrategy implements RejectStrategy&#123;
    @Override
    public void reject(String message, Map&lt;String, Object&gt; paramMap, Fix fix) &#123;
        Set&lt;String&gt; paramKetSet= paramMap.keySet();
        if(!paramKetSet.containsAll(PlaceHolderUtils.keySet(message,fix)))&#123;
            log.error(&quot;消息占位符替换参数与消息模版不完全匹配，message = &#123;&#125;,param = &#123;&#125;&quot;,message,paramMap);
            throw new RuntimeException(&quot;消息占位符替换参数与消息模版不完全匹配&quot;);
        &#125;
    &#125;
&#125;
</code></pre>
</li>
<li><p>定义策略工厂</p>
<pre><code class="prettyprint">public class RejectStrategyFactory &#123;
    private static final IgnoreRejectStrategy IGNORE_REJECT_STRATEGY = new IgnoreRejectStrategy();
    private static final AnyMatchStrategy ANY_MATCH_STRATEGY = new AnyMatchStrategy();
    private static final TotallyMatchStrategy TOTALLY_MATCH_STRATEGY = new TotallyMatchStrategy();

    private RejectStrategyFactory()&#123;&#125;
    public static RejectStrategy getRejectStrategy(RejectStrategyEnum rejectStrategyEnum)&#123;
        switch (rejectStrategyEnum)&#123;
            case IGNORE:
                return IGNORE_REJECT_STRATEGY;
            case ANY_MATCH:
                return ANY_MATCH_STRATEGY;
            case TOTALLY_MATCH:
                return TOTALLY_MATCH_STRATEGY;
            default:
                throw new IllegalArgumentException(&quot;Illegal StrategyEnum Param&quot;);
        &#125;
    &#125;
    public static RejectStrategy getRejectStrategy()&#123;
        return IGNORE_REJECT_STRATEGY;
    &#125;
&#125;
public enum RejectStrategyEnum &#123;
    /*忽略，部分匹配，全匹配*/
    IGNORE,
    ANY_MATCH,
    TOTALLY_MATCH
&#125;
</code></pre>
</li>
<li><p>其他消息策略相关类</p>
<pre><code class="prettyprint">public class PlaceHolderUtils &#123;
    public static String replacePlaceholder(String message, Map&lt;String,Object&gt; paramMap, Fix fix)&#123;
        for(Map.Entry&lt;String, Object&gt; entry:paramMap.entrySet())&#123;
            message = message.replace(fix.getPrefix()+entry.getKey()+fix.getSuffix(), entry.getValue() == null ?&quot;&quot;:(CharSequence) entry.getValue() );
        &#125;
        return message;
    &#125;
    public static Set&lt;String&gt; keySet(String message, Fix fix)&#123;
        Set&lt;String&gt; strings = new HashSet&lt;&gt;();
        if(StringUtils.isNotBlank(message))&#123;
            while(message.indexOf(fix.getPrefix()) &gt; 0)&#123;
                int beg = message.indexOf(fix.getPrefix())+fix.getPrefix().length();
                int end = message.indexOf(fix.getSuffix());
                String sub = message.substring(beg, end);
                message = message.substring(end+fix.getSuffix().length());
                String param = sub.replace(fix.getPrefix(), &quot;&quot;).replace(fix.getSuffix(), &quot;&quot;);
                strings.add(param);
            &#125;
        &#125;
        return strings;
    &#125;
&#125;
// 消息参数替换格式
public class Fix &#123;
    private String prefix = &quot;&#123;&quot;;
    private String suffix = &quot;&#125;&quot;;

    public String getPrefix() &#123;
        return prefix;
    &#125;

    public void setPrefix(String prefix) &#123;
        this.prefix = prefix;
    &#125;

    public String getSuffix() &#123;
        return suffix;
    &#125;

    public void setSuffix(String suffix) &#123;
        this.suffix = suffix;
    &#125;
&#125;
// 消息模板处理接口
public interface TemplatePlaceHolderHandler &#123;
    String handler(String message, Map&lt;String,Object&gt; paramMap, Fix fix);
&#125;
// 消息模板，默认处理规则
public class DefaultTemplatePlaceHolderHandler implements TemplatePlaceHolderHandler&#123;
    private RejectStrategy rejectStrategy;

    public DefaultTemplatePlaceHolderHandler(RejectStrategy rejectStrategy) &#123;
        this.rejectStrategy = rejectStrategy;
    &#125;

    @Override
    public String handler(String message, Map&lt;String, Object&gt; paramMap, Fix fix) &#123;
        rejectStrategy.reject(message,paramMap,fix);
        return PlaceHolderUtils.replacePlaceholder(message,paramMap,fix);
    &#125;
&#125;
</code></pre>
</li>
<li><p>测试调用</p>
<pre><code class="prettyprint">// 获取对应策略对象
    private TemplatePlaceHolderHandler placeholder1 = new DefaultTemplatePlaceHolderHandler(RejectStrategyFactory.getRejectStrategy(RejectStrategyEnum.IGNORE));
// 执行方法
 String content = placeholder1.handler(messages.get(5), paramMap, commonProperties.getFix());
</code></pre>
</li>
</ul>
<h3 id="模板模式"><a href="#模板模式" class="headerlink" title="模板模式"></a>模板模式</h3><blockquote>
<p> <strong>定义：</strong>定义一个操作中算法的骨架，而将一些步骤延迟到子类中，模板方法使得子类可以不改变算法的结构即可重定义该算法的某些特定步骤。 </p>
<p> 完成一件事情，有固定的数个步骤，但是每个步骤根据对象的不同，而实现细节不同；就可以在父类中定义一个完成该事情的总方法，按照完成事件需要的步骤去调用其每个步骤的实现方法。每个步骤的具体实现，由子类完成。 </p>
</blockquote>
<ul>
<li>抽象的做菜父类：</li>
</ul>
<pre><code class="prettyprint">public abstract class Dish &#123;
    /**
     * 具体的整个过程
     */
    protected void doDish()&#123;
        this.preparation();
        this.doing();
        this.carriedDishes();
    &#125;
    /**
     * 备料
     */
    public abstract void preparation();
    /**
     * 做菜
     */
    public abstract void doing();
    /**
     * 上菜
     */
    public abstract void carriedDishes ();
&#125;
</code></pre>
<ul>
<li>番茄炒蛋（EggsWithTomato）和红烧肉（Bouilli）实现父类中的抽象方法</li>
</ul>
<pre><code class="prettyprint">public class EggsWithTomato extends Dish &#123;

    @Override
    public void preparation() &#123;
        System.out.println(&quot;洗并切西红柿，打鸡蛋。&quot;);
    &#125;

    @Override
    public void doing() &#123;
        System.out.println(&quot;鸡蛋倒入锅里，然后倒入西红柿一起炒。&quot;);
    &#125;

    @Override
    public void carriedDishes() &#123;
        System.out.println(&quot;将炒好的西红寺鸡蛋装入碟子里，端给客人吃。&quot;);
    &#125;

&#125;
</code></pre>
<pre><code class="prettyprint">public class Bouilli extends Dish&#123;

    @Override
    public void preparation() &#123;
        System.out.println(&quot;切猪肉和土豆。&quot;);
    &#125;

    @Override
    public void doing() &#123;
        System.out.println(&quot;将切好的猪肉倒入锅中炒一会然后倒入土豆连炒带炖。&quot;);
    &#125;

    @Override
    public void carriedDishes() &#123;
        System.out.println(&quot;将做好的红烧肉盛进碗里端给客人吃。&quot;);
    &#125;

&#125;
</code></pre>
<ul>
<li>在测试类中我们来做菜：</li>
</ul>
<pre><code class="prettyprint">public class MainTest &#123;
    public static void main(String[] args) &#123;
        Dish eggsWithTomato = new EggsWithTomato();
        eggsWithTomato.doDish();

        System.out.println(&quot;-----------------------------&quot;);

        Dish bouilli = new Bouilli();
        bouilli.doDish();
    &#125;

&#125;
/**
 * 洗并切西红柿，打鸡蛋。
 * 鸡蛋倒入锅里，然后倒入西红柿一起炒。
 * 将炒好的西红寺鸡蛋装入碟子里，端给客人吃。
 * -----------------------------
 * 切猪肉和土豆。
 * 将切好的猪肉倒入锅中炒一会然后倒入土豆连炒带炖。
 * 将做好的红烧肉盛进碗里端给客人吃。
 */
</code></pre>
<blockquote>
<p><strong>优点：</strong></p>
<ul>
<li>具体细节步骤实现定义在子类中，子类定义详细处理算法是不会改变算法整体结构。</li>
<li>代码复用的基本技术，在数据库设计中尤为重要。</li>
<li>存在一种反向的控制结构，通过一个父类调用其子类的操作，通过子类对父类进行扩展增加新的行为，符合“开闭原则”。</li>
</ul>
<p><strong>缺点：</strong></p>
<ul>
<li>每个不同的实现都需要定义一个子类，会导致类的个数增加，系统更加庞大。</li>
</ul>
</blockquote>
<h3 id="观察者模式"><a href="#观察者模式" class="headerlink" title="观察者模式"></a>观察者模式</h3><blockquote>
<p> <strong>定义：</strong> 定义对象间的一种一对多的依赖关系，当一个对象的状态发生改变时，所有依赖于它的对象都得到通知并被自动更新。 (广播)</p>
<p> <strong>主要解决：</strong>一个对象状态改变给其他对象通知的问题，而且要考虑到易用和低耦合，保证高度的协作。 </p>
<p> <strong>关键代码：</strong>在抽象类里有一个 ArrayList 存放观察者们。</p>
</blockquote>
<h4 id="模式结构图和代码示例"><a href="#模式结构图和代码示例" class="headerlink" title="模式结构图和代码示例"></a>模式结构图和代码示例</h4><ul>
<li><strong>抽象被观察者角色：</strong>也就是一个抽象主题，它把所有对观察者对象的引用保存在一个集合中，每个主题都可以有任意数量的观察者。抽象主题提供一个接口，可以增加和删除观察者角色。一般用一个抽象类和接口来实现。</li>
<li><strong>抽象观察者角色：</strong>为所有的具体观察者定义一个接口，在得到主题通知时更新自己</li>
<li><strong>具体被观察者角色：</strong>也就是一个具体的主题，在集体主题的内部状态改变时，所有登记过的观察者发出通知。</li>
<li><strong>具体观察者角色：</strong>实现抽象观察者角色所需要的更新接口，一边使本身的状态与制图的状态相协调。</li>
</ul>
<ol>
<li><p>定义一个抽象被观察者接口<code>Subject </code></p>
<pre><code class="prettyprint">public interface Subject &#123;
    public void registerObserver(Observer o);
    public void removeObserver(Observer o);
    public void notifyObserver();
&#125;
</code></pre>
</li>
<li><p>定义一个抽象观察者接口</p>
<pre><code class="prettyprint">public interface Observer &#123;
    public void update(String message);
&#125;
</code></pre>
</li>
<li><p>定义被观察者，实现了Subject接口，对Subject接口的三个方法进行了具体实现，同时有一个List集合，用以保存注册的观察者，等需要通知观察者时，遍历该集合即可。</p>
</li>
</ol>
<pre><code class="prettyprint">public class WechatServer implements Subject &#123;

    private List&lt;Observer&gt; list;
    private String message;

    public WechatServer() &#123;
        list = new ArrayList&lt;Observer&gt;();
    &#125;

    @Override
    public void registerObserver(Observer o) &#123;
        list.add(o);
    &#125;

    @Override
    public void removeObserver(Observer o) &#123;
        if (!list.isEmpty()) &#123;
            list.remove(o);
        &#125;
    &#125;

    @Override
    public void notifyObserver() &#123;
        for (Observer o : list) &#123;
            o.update(message);
        &#125;
    &#125;

    public void setInfomation(String s) &#123;
        this.message = s;
        System.out.println(&quot;微信服务更新消息： &quot; + s);
        // 消息更新，通知所有观察者
        notifyObserver();
    &#125;

&#125;
</code></pre>
<ol start="4">
<li>定义具体观察者，微信公众号的具体观察者为用户User</li>
</ol>
<pre><code class="prettyprint">public class User implements Observer &#123;

    private String name;
    private String message;

    public User(String name) &#123;
        this.name = name;
    &#125;

    @Override
    public void update(String message) &#123;
        this.message = message;
        read();
    &#125;

    public void read() &#123;
        System.out.println(name + &quot; 收到推送消息： &quot; + message);
    &#125;

&#125;
</code></pre>
<ol start="5">
<li><p>测试</p>
<pre><code class="prettyprint">public class MainTest &#123;
    public static void main(String[] args) &#123;

        WechatServer server = new WechatServer();

        Observer userZhang = new User(&quot;ZhangSan&quot;);
        Observer userLi = new User(&quot;LiSi&quot;);
        Observer userWang = new User(&quot;WangWu&quot;);

        server.registerObserver(userZhang);
        server.registerObserver(userLi);
        server.registerObserver(userWang);
        server.setInfomation(&quot;PHP是世界上最好用的语言！&quot;);

        System.out.println(&quot;----------------------------------------------&quot;);
        server.removeObserver(userZhang);
        server.setInfomation(&quot;JAVA是世界上最好用的语言！&quot;);

    &#125;
&#125;
/**
 * 微信服务更新消息： PHP是世界上最好用的语言！
 * ZhangSan 收到推送消息： PHP是世界上最好用的语言！
 * LiSi 收到推送消息： PHP是世界上最好用的语言！
 * WangWu 收到推送消息： PHP是世界上最好用的语言！
 * ----------------------------------------------
 * 微信服务更新消息： JAVA是世界上最好用的语言！
 * LiSi 收到推送消息： JAVA是世界上最好用的语言！
 * WangWu 收到推送消息： JAVA是世界上最好用的语言！
 */
</code></pre>
</li>
</ol>
<blockquote>
<p><strong>优点：</strong></p>
<ul>
<li><p>观察者和被观察者是抽象耦合的。</p>
</li>
<li><p>建立一套触发机制。</p>
</li>
</ul>
<p><strong>缺点：</strong></p>
<ul>
<li><p>如果一个被观察者对象有很多的直接和间接的观察者的话，将所有的观察者都通知到会花费很多时间。</p>
</li>
<li><p>如果在观察者和观察目标之间有循环依赖的话，观察目标会触发它们之间进行循环调用，可能导致系统崩溃。</p>
</li>
<li><p>观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的，而仅仅只是知道观察目标发生了变化。</p>
</li>
</ul>
</blockquote>
<h3 id="迭代器模式"><a href="#迭代器模式" class="headerlink" title="迭代器模式"></a>迭代器模式</h3><blockquote>
<p><strong>定义：</strong>提供一种方法顺序访问一个聚合对象中各个元素, 而又无须暴露该对象的内部表示。</p>
<p><strong>优点：</strong> </p>
<ul>
<li><p>它支持以不同的方式遍历一个聚合对象。</p>
</li>
<li><p>迭代器简化了聚合类。</p>
</li>
<li><p>在同一个聚合上可以有多个遍历。</p>
</li>
<li><p>在迭代器模式中，增加新的聚合类和迭代器类都很方便，无须修改原有代码。</p>
</li>
</ul>
<p><strong>缺点：</strong>由于迭代器模式将存储数据和遍历数据的职责分离，增加新的聚合类需要对应增加新的迭代器类，类的个数成对增加，这在一定程度上增加了系统的复杂性。</p>
<p><strong>关键代码：</strong>定义接口：<code>hasNext()</code>, <code>next()</code>。</p>
</blockquote>
<h4 id="迭代器模式结构和代码示例"><a href="#迭代器模式结构和代码示例" class="headerlink" title="迭代器模式结构和代码示例"></a>迭代器模式结构和代码示例</h4><ul>
<li><p>迭代器角色（<code>Iterator</code>）:定义遍历元素所需要的方法，一般来说会有这么三个方法：取得下一个元素的方法<code>next()</code>，判断是否遍历结束的方法<code>hasNext()</code>，移出当前对象的方法<code>remove()</code></p>
</li>
<li><p>具体迭代器角色（<code>Concrete Iterator</code>）：实现迭代器接口中定义的方法，完成集合的迭代。</p>
</li>
<li><p>容器角色(<code>Aggregate</code>): 一般是一个接口，提供一个<code>iterator()</code>方法，例如java中的<code>Collection</code>接口，<code>List</code>接口，<code>Set</code>接口等</p>
</li>
<li><p>具体容器角色（<code>ConcreteAggregate</code>）：就是抽象容器的具体实现类，比如<code>List</code>接口的有序列表实现<code>ArrayList</code>，&#96;&#96;List接口的链表实现<code>LinkList</code>，<code>Set</code>接口的哈希列表的实现<code>HashSet</code>等。</p>
</li>
</ul>
<ol>
<li><p>迭代器接口</p>
<pre><code class="prettyprint">public interface Iterator &#123;
    public boolean hasNext();
    public Object next();
&#125;
</code></pre>
<pre><code class="prettyprint">@AllArgsConstructor
@Data
public class MenuItem &#123;
    String name;
    String description;
    boolean vegetable;
    float price;
&#125;
</code></pre>
</li>
<li><p>咖啡店菜单和咖啡店菜单遍历器</p>
<pre><code class="prettyprint">public class CakeHouseMenu &#123;
    private ArrayList&lt;MenuItem&gt; menuItems;

    public CakeHouseMenu() &#123;
        menuItems = new ArrayList&lt;MenuItem&gt;();
        addItem(&quot;KFC Cake Breakfast&quot;, &quot;boiled eggs&amp;toast&amp;cabbage&quot;, true, 3.99f);
        addItem(&quot;MDL Cake Breakfast&quot;, &quot;fried eggs&amp;toast&quot;, false, 3.59f);
        addItem(&quot;Stawberry Cake&quot;, &quot;fresh stawberry&quot;, true, 3.29f);
        addItem(&quot;Regular Cake Breakfast&quot;, &quot;toast&amp;sausage&quot;, true, 2.59f);
    &#125;

    private void addItem(String name, String description, boolean vegetable, float price) &#123;
        MenuItem menuItem = new MenuItem(name, description, vegetable, price);
        menuItems.add(menuItem);
    &#125;

    public Iterator getIterator() &#123;
        return new CakeHouseIterator();
    &#125;

    class CakeHouseIterator implements Iterator &#123;
        private int position = 0;

        public CakeHouseIterator() &#123;
            position = 0;
        &#125;

        @Override
        public boolean hasNext() &#123;
            if (position &lt; menuItems.size()) &#123;
                return true;
            &#125;

            return false;
        &#125;

        @Override
        public Object next() &#123;
            MenuItem menuItem = menuItems.get(position);
            position++;
            return menuItem;
        &#125;
    &#125;
&#125;
</code></pre>
</li>
<li><p>中餐厅菜单和中餐厅菜单遍历器</p>
<pre><code class="prettyprint">public class DinerMenu &#123;
    private final static int Max_Items = 5;
    private int numberOfItems = 0;
    private MenuItem[] menuItems;

    public DinerMenu() &#123;
        menuItems = new MenuItem[Max_Items];
        addItem(&quot;vegetable Blt&quot;, &quot;bacon&amp;lettuce&amp;tomato&amp;cabbage&quot;, true, 3.58f);
        addItem(&quot;Blt&quot;, &quot;bacon&amp;lettuce&amp;tomato&quot;, false, 3.00f);
        addItem(&quot;bean soup&quot;, &quot;bean&amp;potato salad&quot;, true, 3.28f);
        addItem(&quot;hotdog&quot;, &quot;onions&amp;cheese&amp;bread&quot;, false, 3.05f);
    &#125;

    private void addItem(String name, String description, boolean vegetable,float price) &#123;
        MenuItem menuItem = new MenuItem(name, description, vegetable, price);
        if (numberOfItems &gt;= Max_Items) &#123;
            System.err.println(&quot;sorry,menu is full!can not add another item&quot;);
        &#125; else &#123;
            menuItems[numberOfItems] = menuItem;
            numberOfItems++;
        &#125;
    &#125;

    public Iterator getIterator() &#123;
        return new DinerIterator();
    &#125;

    class DinerIterator implements Iterator &#123;
        private int position;

        public DinerIterator() &#123;
            position = 0;
        &#125;

        @Override
        public boolean hasNext() &#123;
            if (position &lt; numberOfItems) &#123;
                return true;
            &#125;
            return false;
        &#125;

        @Override
        public Object next() &#123;
            MenuItem menuItem = menuItems[position];
            position++;
            return menuItem;
        &#125;
    &#125;
&#125;
</code></pre>
</li>
<li><p>服务员上菜</p>
<pre><code class="prettyprint">public class Waitress &#123;
    private ArrayList&lt;Iterator&gt; iterators = new ArrayList&lt;Iterator&gt;();

    public void addIterator(Iterator iterator) &#123;
        iterators.add(iterator);
    &#125;

    public void printMenu() &#123;
        Iterator iterator;
        MenuItem menuItem;
        for (int i = 0, len = iterators.size(); i &lt; len; i++) &#123;
            iterator = iterators.get(i);
            while (iterator.hasNext()) &#123;
                menuItem = (MenuItem) iterator.next();
                System.out.println(menuItem.getName() + &quot;----------&quot; + menuItem.getPrice() + &quot;----------&quot; + menuItem.getDescription());
            &#125;
            System.out.println(&quot;------------------------------------------------&quot;);
        &#125;
    &#125;
&#125;
</code></pre>
</li>
<li><p>测试</p>
<pre><code class="prettyprint">public class MainTest &#123;
    public static void main(String[] args) &#123;
        Waitress waitress = new Waitress();
        waitress.addIterator(new CakeHouseMenu().getIterator());
        waitress.addIterator(new DinerMenu().getIterator());
        waitress.printMenu();
    &#125;
&#125;
/**
 * KFC Cake Breakfast----------3.99----------boiled eggs&amp;toast&amp;cabbage
 * MDL Cake Breakfast----------3.59----------fried eggs&amp;toast
 * Stawberry Cake----------3.29----------fresh stawberry
 * Regular Cake Breakfast----------2.59----------toast&amp;sausage
 * ------------------------------------------------
 * vegetable Blt----------3.58----------bacon&amp;lettuce&amp;tomato&amp;cabbage
 * Blt----------3.0----------bacon&amp;lettuce&amp;tomato
 * bean soup----------3.28----------bean&amp;potato salad
 * hotdog----------3.05----------onions&amp;cheese&amp;bread
 */
</code></pre>
</li>
</ol>
<h3 id="责任链模式"><a href="#责任链模式" class="headerlink" title="责任链模式"></a>责任链模式</h3><blockquote>
<p><strong>定义：</strong>如果有多个对象有机会处理请求，责任链可使请求的发送者和接受者解耦，请求沿着责任链传递，直到有一个对象处理了它为止。</p>
<p><strong>主要解决：</strong>职责链上的处理者负责处理请求，客户只需要将请求发送到职责链上即可，无须关心请求的处理细节和请求的传递，所以职责链将请求的发送者和请求的处理者解耦了。</p>
<p><strong>关键代码：</strong><code>Handler</code> 里面聚合它自己，在 <code>HandlerRequest </code>里判断是否合适，如果没达到条件则向下传递，向谁传递之前<code>set</code>进去。</p>
</blockquote>
<h4 id="责任链模式的结构和代码示例"><a href="#责任链模式的结构和代码示例" class="headerlink" title="责任链模式的结构和代码示例"></a>责任链模式的结构和代码示例</h4><ul>
<li>抽象处理者<code>Handler</code>角色：定义一个处理请求的接口，包含抽象处理方法和一个<strong>后继连接</strong>。</li>
<li>具体处理者<code>Concrete Handler</code>角色：实现抽象处理者的处理方法，判断能否处理本次请求，如果可以处理请求则处理，否则将该请求转给它的后继者。</li>
<li>客户类<code>Client</code>角色：创建处理链，并向链头的具体处理者对象提交请求，它不关心处理细节和请求的传递过程。</li>
</ul>
<ol>
<li><p>决策者抽象类，包含对请求处理的函数，同时还包含指定下一个决策者的函数</p>
<pre><code class="prettyprint">public abstract class Approver &#123;
    Approver successor;
    String Name;

    public Approver(String Name) &#123;
        this.Name = Name;
    &#125;

    public abstract void ProcessRequest(PurchaseRequest request);

    public void SetSuccessor(Approver successor) &#123;
        this.successor = successor;
    &#125;
&#125;
</code></pre>
</li>
<li><p>客户端以及请求</p>
<pre><code class="prettyprint">public class PurchaseRequest &#123;
    private int Type = 0;
    private int Number = 0;
    private float Price = 0;
    private int ID = 0;

    public PurchaseRequest(int Type, int Number, float Price) &#123;
        this.Type = Type;
        this.Number = Number;
        this.Price = Price;
    &#125;

    public int GetType() &#123;
        return Type;
    &#125;

    public float GetSum() &#123;
        return Number * Price;
    &#125;

    public int GetID() &#123;
        return (int) (Math.random() * 1000);
    &#125;
&#125;
public class Client &#123;

    public PurchaseRequest sendRequest(int Type, int Number, float Price) &#123;
        return new PurchaseRequest(Type, Number, Price);
    &#125;

&#125;
</code></pre>
</li>
<li><p>组长、部长。。。继承决策者抽象类</p>
<pre><code class="prettyprint">public class GroupApprover extends Approver &#123;

    public GroupApprover(String Name) &#123;
        super(Name + &quot; GroupLeader&quot;);
    &#125;

    @Override
    public void ProcessRequest(PurchaseRequest request) &#123;
        if (request.GetSum() &lt; 5000) &#123;
            System.out.println(&quot;**This request &quot; + request.GetID() + &quot; will be handled by &quot; + this.Name + &quot; **&quot;);
        &#125; else &#123;
            successor.ProcessRequest(request);
        &#125;
    &#125;

&#125;
public class DepartmentApprover extends Approver &#123;

    public DepartmentApprover(String Name) &#123;
        super(Name + &quot; DepartmentLeader&quot;);
    &#125;

    @Override
    public void ProcessRequest(PurchaseRequest request) &#123;
        if ((5000 &lt;= request.GetSum()) &amp;&amp; (request.GetSum() &lt; 10000)) &#123;
            System.out.println(&quot;**This request &quot; + request.GetID()
                    + &quot; will be handled by &quot; + this.Name + &quot; **&quot;);
        &#125; else &#123;
            successor.ProcessRequest(request);
        &#125;
    &#125;
&#125;
public class VicePresidentApprover extends Approver &#123;

    public VicePresidentApprover(String Name) &#123;
        super(Name + &quot; VicePresidentmentLeader&quot;);
    &#125;

    @Override
    public void ProcessRequest(PurchaseRequest request) &#123;
        if ((10000 &lt;= request.GetSum()) &amp;&amp; (request.GetSum() &lt; 20000)) &#123;
            System.out.println(&quot;**This request &quot; + request.GetID()
                    + &quot; will be handled by &quot; + this.Name + &quot; **&quot;);
        &#125; else &#123;
            successor.ProcessRequest(request);
        &#125;
    &#125;
&#125;
public class PresidentApprover extends Approver &#123;
    public PresidentApprover(String Name) &#123;
        super(Name + &quot; PresidentLeader&quot;);
    &#125;

    @Override
    public void ProcessRequest(PurchaseRequest request) &#123;
        if ((20000 &lt;= request.GetSum())) &#123;
            System.out.println(&quot;**This request &quot; + request.GetID()
                    + &quot; will be handled by &quot; + this.Name + &quot; **&quot;);
        &#125; else &#123;
            successor.ProcessRequest(request);
        &#125;
    &#125;
&#125;
</code></pre>
</li>
<li><p>测试</p>
<pre><code class="prettyprint">public class MainTest &#123;
    public static void main(String[] args) &#123;
        Client mClient = new Client();
        Approver GroupLeader = new GroupApprover(&quot;Tom&quot;);
        Approver VicePresident = new VicePresidentApprover(&quot;Kate&quot;);
        Approver DepartmentLeader = new DepartmentApprover(&quot;Jerry&quot;);
        Approver President = new PresidentApprover(&quot;Bush&quot;);
        /*组长、副部、部长、总裁*/
        GroupLeader.SetSuccessor(VicePresident);
        VicePresident.SetSuccessor(DepartmentLeader);
        DepartmentLeader.SetSuccessor(President);
        President.SetSuccessor(GroupLeader);
        GroupLeader.ProcessRequest(mClient.sendRequest(1, 400, 40));
    &#125;
&#125;
</code></pre>
</li>
</ol>
<h3 id="命令模式"><a href="#命令模式" class="headerlink" title="命令模式"></a>命令模式</h3><blockquote>
<p><strong>定义：</strong>将一个请求封装为一个对象，使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通，这样方便将命令对象进行储存、传递、调用、增加与管理。 </p>
<p><strong>主要解决：</strong>在软件系统中，行为请求者与行为实现者通常是一种紧耦合的关系，但某些场合，比如需要对行为进行记录、撤销或重做、事务等处理时，这种无法抵御变化的紧耦合的设计就不太合适。 </p>
</blockquote>
<h4 id="命令模式结构和代码示例"><a href="#命令模式结构和代码示例" class="headerlink" title="命令模式结构和代码示例"></a>命令模式结构和代码示例</h4><ul>
<li>抽象命令类 <code>Command</code> 角色：声明执行命令的接口，拥有执行命令的抽象方法 <code>execute()</code>。</li>
<li>具体命令角色 <code>Concrete Command</code> 角色：是抽象命令类的具体实现类，它拥有接收者对象，并通过调用接收者的功能来完成命令要执行的操作。</li>
<li>实现者&#x2F;接收者 <code>Receiver</code>角色：执行命令功能的相关操作，是具体命令对象业务的真正实现者。</li>
<li>调用者&#x2F;请求者 <code>Invoke</code> 角色：是请求的发送者，它通常拥有很多的命令对象，并通过访问命令对象来执行相关请求，它不直接访问接收者。</li>
</ul>
<p><strong>举例：关灯</strong></p>
<ol>
<li>命令抽象类</li>
</ol>
<pre><code class="prettyprint">public interface Command &#123;
    public void execute();
    public void undo();
&#125;
</code></pre>
<ol start="2">
<li><p>具体命令对象</p>
<pre><code class="prettyprint">public class TurnOffLight implements Command &#123;

    private Light light;

    public TurnOffLight(Light light) &#123;
        this.light = light;
    &#125;

    @Override
    public void execute() &#123;
        light.Off();
    &#125;

    @Override
    public void undo() &#123;
        light.On();
    &#125;

&#125;
</code></pre>
</li>
<li><p>实现者</p>
<pre><code class="prettyprint">public class Light &#123;

    String loc = &quot;&quot;;

    public Light(String loc) &#123;
        this.loc = loc;
    &#125;

    public void On() &#123;

        System.out.println(loc + &quot; On&quot;);
    &#125;

    public void Off() &#123;

        System.out.println(loc + &quot; Off&quot;);
    &#125;

&#125;
</code></pre>
</li>
<li><p>请求者</p>
<pre><code class="prettyprint">public class Controller &#123;
    public void commandExecute(Command command) &#123;
        command.execute();
    &#125;

    public void commandUndo(Command command) &#123;
        command.undo();
    &#125;
&#125;
</code></pre>
</li>
<li><p>测试</p>
<pre><code class="prettyprint">public class MainTest &#123;
    public static void main(String[] args) &#123;
        Controller controller = new Controller();
        TurnOffLight turnOffLight = new TurnOffLight(new Light(&quot;roc&quot;));
        controller.commandUndo(turnOffLight);
        controller.commandExecute(turnOffLight);
    &#125;
&#125;
</code></pre>
</li>
</ol>
<h3 id="状态模式"><a href="#状态模式" class="headerlink" title="状态模式"></a>状态模式</h3><blockquote>
<p><strong>定义：</strong> 在状态模式中，我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 <code>context</code> 对象。 </p>
<p><strong>主要解决：</strong>对象的行为依赖于它的状态（属性），并且可以根据它的状态改变而改变它的相关行为。</p>
<p><strong>关键代码：</strong>通常命令模式的接口中只有一个方法。而状态模式的接口中有一个或者多个方法。而且，状态模式的实现类的方法，一般返回值，或者是改变实例变量的值。也就是说，状态模式一般和对象的状态有关。实现类的方法有不同的功能，覆盖接口中的方法。状态模式和命令模式一样，也可以用于消除 if…else 等条件选择语句。  </p>
</blockquote>
<p><strong>优点：</strong> </p>
<ul>
<li><p>封装了转换规则。 </p>
</li>
<li><p>枚举可能的状态，在枚举状态之前需要确定状态种类。 </p>
</li>
<li><p>将所有与某个状态有关的行为放到一个类中，并且可以方便地增加新的状态，只需要改变对象状态即可改变对象的行为。</p>
</li>
<li><p>允许状态转换逻辑与状态对象合成一体，而不是某一个巨大的条件语句块。</p>
</li>
<li><p>可以让多个环境对象共享一个状态对象，从而减少系统中对象的个数。</p>
</li>
</ul>
<p><strong>缺点:</strong></p>
<ul>
<li>状态模式的使用必然会增加系统类和对象的个数。 </li>
<li>状态模式的结构与实现都较为复杂，如果使用不当将导致程序结构和代码的混乱。 </li>
<li>状态模式对”开闭原则”的支持并不太好，对于可以切换状态的状态模式，增加新的状态类需要修改那些负责状态转换的源代码，否则无法切换到新增状态，而且修改某个状态类的行为也需修改对应类的源代码。</li>
</ul>
<h4 id="状态模式结构和代码示例"><a href="#状态模式结构和代码示例" class="headerlink" title="状态模式结构和代码示例"></a>状态模式结构和代码示例</h4><ul>
<li><strong>State抽象状态角色</strong></li>
</ul>
<p>接口或抽象类，负责对象状态定义，并且封装环境角色以实现状态切换。</p>
<ul>
<li><strong>ConcreteState具体状态角色</strong></li>
</ul>
<p>具体状态主要有两个职责：一是处理本状态下的事情，二是从本状态如何过渡到其他状态。</p>
<ul>
<li><strong>Context环境角色</strong></li>
</ul>
<p>定义客户端需要的接口，并且负责具体状态的切换。</p>
<ol>
<li><p><code>state</code> 抽象接口</p>
<pre><code class="prettyprint">public interface State &#123;
    public void doAction(Context context);
&#125;
</code></pre>
</li>
<li><p>状态实例</p>
<pre><code class="prettyprint">public class StartState implements State &#123;

    @Override
    public void doAction(Context context) &#123;
        System.out.println(&quot;Player is in start state&quot;);
        context.setState(this);
    &#125;

    @Override
    public String toString()&#123;
        return &quot;Start State&quot;;
    &#125;
&#125;
</code></pre>
<pre><code class="prettyprint">public class StopState implements State &#123;

    @Override
    public void doAction(Context context) &#123;
        System.out.println(&quot;Player is in stop state&quot;);
        context.setState(this);
    &#125;

    @Override
    public String toString()&#123;
        return &quot;Stop State&quot;;
    &#125;
&#125;
</code></pre>
</li>
<li><p><code>context(player)</code>拥有状态的对象 </p>
<pre><code class="prettyprint">public class Context &#123;
    private State state;

    public Context()&#123;
        state = null;
    &#125;

    public void setState(State state)&#123;
        this.state = state;
    &#125;

    public State getState()&#123;
        return state;
    &#125;
&#125;
</code></pre>
</li>
<li><p>测试</p>
<pre><code class="prettyprint">public class MainTest &#123;
    public static void main(String[] args) &#123;
        Context context = new Context();
        StartState startState = new StartState();
        startState.doAction(context);
        System.out.println(context.getState().toString());
        StopState stopState = new StopState();
        stopState.doAction(context);
        System.out.println(context.getState().toString());
    &#125;
&#125;
/**
 * Player is in start state
 * Start State
 * Player is in stop state
 * Stop State
 */
</code></pre>
</li>
</ol>
<h3 id="备忘录模式"><a href="#备忘录模式" class="headerlink" title="备忘录模式"></a>备忘录模式</h3><blockquote>
<p><strong>定义：</strong> 在不破坏封装性的前提下，捕获一个对象的内部状态，并在该对象之外保存这个状态，以便以后当需要时能将该对象恢复到原先保存的状态。该模式又叫快照模式。备忘录模式是一种对象行为型模式 </p>
</blockquote>
<p><strong>优点：</strong></p>
<ul>
<li>提供了一种可以恢复状态的机制。当用户需要时能够比较方便地将数据恢复到某个历史的状态。</li>
<li>实现了内部状态的封装。除了创建它的发起人之外，其他对象都不能够访问这些状态信息。</li>
<li>简化了发起人类。发起人不需要管理和保存其内部状态的各个备份，所有状态信息都保存在备忘录中，并由管理者进行管理，这符合单一职责原则。</li>
</ul>
<p><strong>缺点：</strong></p>
<ul>
<li>资源消耗大。如果要保存的内部状态信息过多或者特别频繁，将会占用比较大的内存资源。</li>
</ul>
<h4 id="备忘录模式结构图和代码示例"><a href="#备忘录模式结构图和代码示例" class="headerlink" title="备忘录模式结构图和代码示例"></a>备忘录模式结构图和代码示例</h4><ul>
<li>发起人 <code>Originator</code> 角色：记录当前时刻的内部状态信息，提供创建备忘录和恢复备忘录数据的功能，实现其他业务功能，它可以访问备忘录里的所有信息。</li>
<li>备忘录 <code>Memento</code> 角色：负责存储发起人的内部状态，在需要的时候提供这些内部状态给发起人。</li>
<li>管理者 <code>Caretaker</code> 角色：对备忘录进行管理，提供保存与获取备忘录的功能，但其不能对备忘录的内容进行访问与修改。</li>
</ul>
<ol>
<li><p>备忘录接口</p>
<pre><code class="prettyprint">public interface MementoIf &#123;
&#125;
</code></pre>
</li>
<li><p>备忘录</p>
<pre><code class="prettyprint">public class Memento implements MementoIf&#123;
    private String state;

    public Memento(String state) &#123;
        this.state = state;
    &#125;

    public String getState()&#123;
        return state;
    &#125;
&#125;
</code></pre>
</li>
<li><p>发起者(状态变更)</p>
<pre><code class="prettyprint">public class Originator &#123;
    private String state;

    public String getState() &#123;
        return state;
    &#125;

    public void setState(String state) &#123;
        this.state = state;
    &#125;

    public Memento saveStateToMemento() &#123;
        return new Memento(state);
    &#125;

    public String getStateFromMemento(MementoIf memento) &#123;
        return ((Memento) memento).getState();
    &#125;
&#125;
</code></pre>
</li>
<li><p>管理者(备份)</p>
<pre><code class="prettyprint">public class CareTaker &#123;
    private List&lt;MementoIf&gt; mementoList = new ArrayList&lt;MementoIf&gt;();

    public void add(MementoIf memento) &#123;
        mementoList.add(memento);
    &#125;

    public MementoIf get(int index) &#123;
        return mementoList.get(index);
    &#125;
&#125;
</code></pre>
</li>
<li><p>测试</p>
<pre><code class="prettyprint">public class MainTest &#123;
    public static void main(String[] args) &#123;
        Originator originator = new Originator();
        CareTaker careTaker = new CareTaker();
        originator.setState(&quot;State #1&quot;);
        originator.setState(&quot;State #2&quot;);
        careTaker.add(originator.saveStateToMemento());
        originator.setState(&quot;State #3&quot;);
        careTaker.add(originator.saveStateToMemento());
        originator.setState(&quot;State #4&quot;);

        System.out.println(&quot;Current State: &quot; + originator.getState());
        System.out.println(&quot;First saved State: &quot; + originator.getStateFromMemento(careTaker.get(0)));
        System.out.println(&quot;Second saved State: &quot; + originator.getStateFromMemento(careTaker.get(1)));
    &#125;
&#125;
/**
 * Current State: State #4
 * First saved State: State #2
 * Second saved State: State #3
 */
</code></pre>
</li>
</ol>
<h3 id="访问者模式"><a href="#访问者模式" class="headerlink" title="访问者模式"></a>访问者模式</h3><blockquote>
<p><strong>定义：</strong> 将作用于某种数据结构中的各元素的操作分离出来封装成独立的类，使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作，为数据结构中的每个元素提供多种访问方式。它将对数据的操作与数据结构进行分离。 </p>
</blockquote>
<p><strong>优点：</strong></p>
<ul>
<li>扩展性好。能够在不修改对象结构中的元素的情况下，为对象结构中的元素添加新的功能。</li>
<li>复用性好。可以通过访问者来定义整个对象结构通用的功能，从而提高系统的复用程度。</li>
<li>灵活性好。访问者模式将数据结构与作用于结构上的操作解耦，使得操作集合可相对自由地演化而不影响系统的数据结构。</li>
<li>符合单一职责原则。访问者模式把相关的行为封装在一起，构成一个访问者，使每一个访问者的功能都比较单一。</li>
</ul>
<p><strong>缺点：</strong></p>
<ul>
<li>增加新的元素类很困难。在访问者模式中，每增加一个新的元素类，都要在每一个具体访问者类中增加相应的具体操作，这违背了“开闭原则”。</li>
<li>破坏封装。访问者模式中具体元素对访问者公布细节，这破坏了对象的封装性。</li>
<li>违反了依赖倒置原则。访问者模式依赖了具体类，而没有依赖抽象类。</li>
</ul>
<h4 id="访问者模式结构和代码示例"><a href="#访问者模式结构和代码示例" class="headerlink" title="访问者模式结构和代码示例"></a>访问者模式结构和代码示例</h4><ul>
<li><p>抽象访问者 <code>Visitor</code> 角色：定义一个访问具体元素的接口，为每个具体元素类对应一个访问操作 <code>visit()</code> ，该操作中的参数类型标识了被访问的具体元素。</p>
</li>
<li><p>具体访问者 <code>ConcreteVisitor</code> 角色：实现抽象访问者角色中声明的各个访问操作，确定访问者访问一个元素时该做什么。</p>
</li>
<li><p>抽象元素 <code>Element</code> 角色：声明一个包含接受操作 <code>accept() </code>的接口，被接受的访问者对象作为 <code>accept() </code>方法的参数。</p>
</li>
<li><p>具体元素 <code>ConcreteElement</code> 角色：实现抽象元素角色提供的 accept() 操作，其方法体通常都是 <code>visitor.visit(this) </code>，另外具体元素中可能还包含本身业务逻辑的相关操作。</p>
</li>
<li><p>对象结构 <code>Object Structure</code> 角色：是一个包含元素角色的容器，提供让访问者对象遍历容器中的所有元素的方法，通常由 <code>List、Set、Map</code> 等聚合类实现。</p>
</li>
</ul>
<ol>
<li><p>抽象访问者</p>
<pre><code class="prettyprint">public interface ComputerPartVisitor   &#123;
    public void visit(Computer computer);
    public void visit(Mouse mouse);
    public void visit(Keyboard keyboard);
    public void visit(Monitor monitor);
&#125;
</code></pre>
</li>
<li><p>具体访问者</p>
<pre><code class="prettyprint">public class ComputerPartDisplayVisitor implements ComputerPartVisitor &#123;

    @Override
    public void visit(Computer computer) &#123;
        System.out.println(&quot;Displaying Computer.&quot;);
    &#125;

    @Override
    public void visit(Mouse mouse) &#123;
        System.out.println(&quot;Displaying Mouse.&quot;);
    &#125;

    @Override
    public void visit(Keyboard keyboard) &#123;
        System.out.println(&quot;Displaying Keyboard.&quot;);
    &#125;

    @Override
    public void visit(Monitor monitor) &#123;
        System.out.println(&quot;Displaying Monitor.&quot;);
    &#125;
&#125;
</code></pre>
</li>
<li><p>抽象元素</p>
<pre><code class="prettyprint">public interface ComputerPart  &#123;
    public void accept(ComputerPartVisitor computerPartVisitor);
&#125;
</code></pre>
</li>
<li><p>具体元素</p>
<pre><code class="prettyprint">public class Keyboard  implements ComputerPart &#123;

    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) &#123;
        computerPartVisitor.visit(this);
    &#125;
&#125;
</code></pre>
<pre><code class="prettyprint">public class Mouse  implements ComputerPart &#123;

    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) &#123;
        computerPartVisitor.visit(this);
    &#125;
&#125;
</code></pre>
<pre><code class="prettyprint">public class Monitor  implements ComputerPart &#123;

    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) &#123;
        computerPartVisitor.visit(this);
    &#125;
&#125;
</code></pre>
</li>
<li><p>对象结构</p>
<pre><code class="prettyprint">public class Computer implements ComputerPart &#123;
    ComputerPart[] parts;

    public Computer()&#123;
        parts = new ComputerPart[] &#123;new Mouse(), new Keyboard(), new Monitor()&#125;;
    &#125;


    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) &#123;
        for (int i = 0; i &lt; parts.length; i++) &#123;
            parts[i].accept(computerPartVisitor);
        &#125;
        computerPartVisitor.visit(this);
    &#125;
&#125;
</code></pre>
</li>
<li><p>测试</p>
<pre><code class="prettyprint">public class MainTest &#123;
    public static void main(String[] args) &#123;
        ComputerPart computer = new Computer();
        computer.accept(new ComputerPartDisplayVisitor());
    &#125;
&#125;
/**
 * Displaying Mouse.
 * Displaying Keyboard.
 * Displaying Monitor.
 * Displaying Computer.
 */
</code></pre>
</li>
</ol>
<h3 id="中介者模式"><a href="#中介者模式" class="headerlink" title="中介者模式"></a>中介者模式</h3><blockquote>
<p> <strong>定义：</strong>定义一个中介对象来封装一系列对象之间的交互，使原有对象之间的耦合松散，且可以独立地改变它们之间的交互。中介者模式又叫调停模式，它是迪米特法则的典型应用。 </p>
</blockquote>
<p><strong>优点：</strong></p>
<ul>
<li>降低了对象之间的耦合性，使得对象易于独立地被复用。 </li>
<li>将对象间的一对多关联转变为一对一的关联，提高系统的灵活性，使得系统易于维护和扩展。</li>
</ul>
<p><strong>缺点：</strong></p>
<ul>
<li>当同事类太多时，中介者的职责将很大，它会变得复杂而庞大，以至于系统难以维护。</li>
</ul>
<h4 id="模中介者式结构和代码示例"><a href="#模中介者式结构和代码示例" class="headerlink" title="模中介者式结构和代码示例"></a>模中介者式结构和代码示例</h4><ul>
<li><p>抽象中介者 <code>Mediator</code> 角色：它是中介者的接口，提供了同事对象注册与转发同事对象信息的抽象方法。</p>
</li>
<li><p>具体中介者 <code>ConcreteMediator</code> 角色：实现中介者接口，定义一个 <code>List </code>来管理同事对象，协调各个同事角色之间的交互关系，因此它依赖于同事角色。</p>
</li>
<li><p>抽象同事类 <code>Colleague</code> 角色：定义同事类的接口，保存中介者对象，提供同事对象交互的抽象方法，实现所有相互影响的同事类的公共功能。</p>
</li>
<li><p>具体同事类 <code>Concrete Colleague</code> 角色：是抽象同事类的实现者，当需要与其他同事对象交互时，由中介者对象负责后续的交互。</p>
</li>
</ul>
<ol>
<li><p>抽象中介者</p>
<pre><code class="prettyprint">public interface Mediator &#123;
    void register(Colleague colleague); // 客户注册
    void relay(String from, String to,String ad); // 转发
&#125;
</code></pre>
</li>
<li><p>具体中介者</p>
<pre><code class="prettyprint">public class ConcreteMediator implements Mediator &#123;
    private List&lt;Colleague&gt; colleagues = new ArrayList&lt;Colleague&gt;();
    @Override
    public void register(Colleague colleague) &#123;
        if (!colleagues.contains(colleague)) &#123;
            colleagues.add(colleague);
            colleague.setMedium(this);
        &#125;
    &#125;
    @Override
    public void relay(String from, String to, String ad) &#123;
        for (Colleague cl : colleagues) &#123;
            String name = cl.getName();
            if (name.equals(to)) &#123;
                cl.receive(from, ad);
            &#125;
        &#125;
    &#125;
&#125;
</code></pre>
</li>
<li><p>抽象同事类</p>
<pre><code class="prettyprint">public abstract class Colleague &#123;
    protected Mediator mediator;
    protected String name;

    public Colleague(String name) &#123;
        this.name = name;
    &#125;

    public void setMedium(Mediator mediator) &#123;
        this.mediator = mediator;
    &#125;

    public String getName() &#123;
        return name;
    &#125;

    public abstract void Send(String to, String ad);

    public abstract void receive(String from, String ad);
&#125;
</code></pre>
</li>
<li><p>具体同事类</p>
<pre><code class="prettyprint">public class Buyer extends Colleague &#123;

    public Buyer(String name) &#123;
        super(name);
    &#125;

    @Override
    public void Send(String to, String ad) &#123;
        mediator.relay(name, to, ad);
    &#125;

    @Override
    public void receive(String from, String ad) &#123;
        System.out.println(name + &quot;接收到来自&quot; + from + &quot;的消息:&quot; + ad);
    &#125;

&#125;
</code></pre>
</li>
<li><p>测试</p>
<pre><code class="prettyprint">public class MainTest &#123;
    public static void main(String[] args) &#123;
        Buyer b = new Buyer(&quot;张三&quot;);
        Buyer c = new Buyer(&quot;李四&quot;);
        ConcreteMediator concreteMediator = new ConcreteMediator();
        concreteMediator.register(b);
        concreteMediator.register(c);
        c.Send(&quot;张三&quot;,&quot;你好张三&quot;);
        b.Send(&quot;李四&quot;,&quot;你好李四&quot;);
    &#125;
&#125;
/**
 * 张三接收到来自李四的消息:你好张三
 * 李四接收到来自张三的消息:你好李四
 */
</code></pre>
</li>
</ol>
<p>参照原文链接：  <a target="_blank" rel="noopener" href="https://blog.csdn.net/A1342772/article/details/91349142">23 种设计模式详解（全23种）_鬼灭之刃的博客-CSDN博客_设计模式</a></p>

      </section>

      
      
        <nav class="article-nav">
          
            <div class="article-nav-item layout-padding">
  <article class="card-container article-nav-card content-padding--primary soft-size--large soft-style--box">
    
      <div class="card-cover" background-image-lazy data-img="https://api.lixingyong.com/api/images?postid=93f6fc65&type=url&itype=image"></div>
    
    <div class="card-text">
      
        <a href="/2023/02/25/yml-wen-jian-yu-fa-shuo-ming/" itemprop="url">
          <h2 class="card-text--title text-ellipsis">yml文件语法说明</h2>
        </a>
      
      <div class="card-text--row">Newer</div>
    </div>
  </article>
</div>
          
          
            <div class="article-nav-item layout-padding">
  <article class="card-container article-nav-card content-padding--primary soft-size--large soft-style--box">
    
      <div class="card-cover" background-image-lazy data-img="https://api.lixingyong.com/api/images?postid=bf1ccec0&type=url&itype=image"></div>
    
    <div class="card-text">
      
        <a href="/2023/02/13/gin-swagger-ce-shi-li-zi/" itemprop="url">
          <h2 class="card-text--title text-ellipsis">gin-swagger测试例子</h2>
        </a>
      
      <div class="card-text--row">Older</div>
    </div>
  </article>
</div>
          
        </nav>
      

      <section class="page-message-container layout-padding">
        


  
  
    <div class="valine-container comments-container content-padding--primary soft-size--large soft-style--box">
      <div id="valine_thread" class="valine-thread"></div>
    </div>
    <script type="text/javascript" src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
    <script type="text/javascript" src='//unpkg.com/valine/dist/Valine.min.js'></script>
    <script type="text/javascript">
      new Valine({
        el: "#valine_thread",
        appId: "yEts8yIOQopn7imcDAmwhlNi-gzGzoHsz",
        appKey: "nyOyHJdsDGQh3UI0TdNdLLnN",
        avatar: "mm",
        placeholder: "随便说点什么叭～",
        notify: true,
        visitor: true,
        pageSize: 10,
      });
    </script>
  

  
  


      </section>
    </div>
    <div class="widget-info">
      <section class="widget-calendar widget-item layout-margin content-padding--primary soft-size--large soft-style--box">
  <div class="widget-body">
	<div id="calendar"></div>
  </div>
</section>

      <section class="widget-categorys widget-item layout-margin content-padding--primary soft-size--large soft-style--box">
  <div class="widget-title">
    <svg class="icon icon-categories" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <path d="M900.3614811 257.09082106h-339.81629553l-67.96326003-101.9448889c-19.41807444-29.12711113-48.54518557-43.69066667-82.52681443-43.69066667H123.6385189c-53.39970333 0-97.09036999 43.69066667-97.09037113 97.09036999v582.54222222c0 53.39970333 43.69066667 97.09036999 97.09037113 97.09037002h776.7229622c53.39970333 0 97.09036999-43.69066667 97.09037113-97.09037002V354.18119104c0-53.39970333-43.69066667-97.09036999-97.09037113-97.09036998z m-97.09036999 242.72592554H220.72888889c-24.27259221 0-48.54518557-24.27259221-48.54518556-48.54518556s24.27259221-48.54518557 48.54518556-48.54518444h582.54222222c24.27259221 0 48.54518557 24.27259221 48.54518556 48.54518444s-24.27259221 48.54518557-48.54518556 48.54518556z" fill="currentColor"></path>
</svg>
    <span>CATEGORYS</span>
  </div>
  <div class="widget-body">
    <ul class="categorys-list">
      
        <li class="categorys-list-item">
          <a href="/categories/%E6%8A%80%E6%9C%AF/">
            技术 (11)
          </a>
        </li>
      
        <li class="categorys-list-item">
          <a href="/categories/%E7%AE%97%E6%B3%95/">
            算法 (15)
          </a>
        </li>
      
        <li class="categorys-list-item">
          <a href="/categories/%E5%B7%A5%E5%85%B7/">
            工具 (3)
          </a>
        </li>
      
        <li class="categorys-list-item">
          <a href="/categories/%E9%97%AE%E9%A2%98/">
            问题 (8)
          </a>
        </li>
      
        <li class="categorys-list-item">
          <a href="/categories/%E8%BD%AF%E4%BB%B6/">
            软件 (31)
          </a>
        </li>
      
        <li class="categorys-list-item">
          <a href="/categories/%E4%B8%AD%E9%97%B4%E4%BB%B6/">
            中间件 (26)
          </a>
        </li>
      
        <li class="categorys-list-item">
          <a href="/categories/%E5%90%8E%E7%AB%AF/">
            后端 (1)
          </a>
        </li>
      
        <li class="categorys-list-item">
          <a href="/categories/java/">
            java (4)
          </a>
        </li>
      
        <li class="categorys-list-item">
          <a href="/categories/%E6%95%B0%E6%8D%AE/">
            数据 (5)
          </a>
        </li>
      
        <li class="categorys-list-item">
          <a href="/categories/linux/">
            linux (3)
          </a>
        </li>
      
        <li class="categorys-list-item">
          <a href="/categories/web/">
            web (1)
          </a>
        </li>
      
        <li class="categorys-list-item">
          <a href="/categories/%E7%89%9B%E8%B7%AF%E6%9D%91/">
            牛路村 (1)
          </a>
        </li>
      
        <li class="categorys-list-item">
          <a href="/categories/%E9%97%B2%E8%B0%88/">
            闲谈 (5)
          </a>
        </li>
      
        <li class="categorys-list-item">
          <a href="/categories/%E5%89%8D%E7%AB%AF/">
            前端 (1)
          </a>
        </li>
      
        <li class="categorys-list-item">
          <a href="/categories/%E5%BE%AE%E4%BF%A1/">
            微信 (1)
          </a>
        </li>
      
        <li class="categorys-list-item">
          <a href="/categories/%E8%8B%A5%E4%BE%9D/">
            若依 (1)
          </a>
        </li>
      
    </ul>
  </div>
</section>

      <section class="widget-tags widget-item  layout-margin content-padding--primary soft-size--large soft-style--box">
  <div class="widget-title">
    <svg class="icon icon-tags" viewBox="0 0 1098 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <path d="M283.42180005 272q0-28.38857157-20.09142843-48.48000001t-48.47999998-20.09142842-48.48000002 20.09142842-20.09142846 48.48000001 20.09142846 48.48 48.48000002 20.09142843 48.47999998-20.09142843 20.09142843-48.48zM855.0332285 580.57142843q0 28.38857157-19.81714313 48.2057147l-263.03999997 263.58857157q-20.9142853 19.81714313-48.75428534 19.81714312-28.38857157 0-48.20571468-19.81714312l-383.04-383.58857157q-20.36571468-19.81714313-34.55999999-54.10285688t-14.19428534-62.6742853l0-222.85714313q0-27.84000002 20.36571469-48.20571469t48.2057147-20.36571466l222.85714313 0q28.38857157 0 62.6742853 14.19428529t54.65142842 34.55999999l383.04000001 382.49142843q19.81714313 20.9142853 19.81714314 48.75428532zM1060.74751475 580.57142843q0 28.38857157-19.81714313 48.2057147l-263.04 263.58857157q-20.9142853 19.81714313-48.75428531 19.81714312-19.26857155 0-31.61142843-7.47428531t-28.38857159-24.13714314l251.79428534-251.7942853q19.81714313-19.81714313 19.81714308-48.20571469 0-27.84000002-19.81714308-48.75428531l-383.04000001-382.49142845q-20.36571468-20.36571468-54.65142842-34.55999999t-62.67428532-14.19428534l120 0q28.38857157 0 62.67428532 14.19428534t54.65142842 34.55999999l383.03999998 382.49142845q19.81714313 20.9142853 19.81714314 48.75428531z" fill="currentColor"></path>
</svg>
    <span>TAGS</span>
  </div>
  <div class="widget-body">
    <div class="tags-cloud">
      <a href="/tags/crontab/" style="font-size: 10px;" class="tags-cloud-0">crontab</a> <a href="/tags/docker/" style="font-size: 20px;" class="tags-cloud-10">docker</a> <a href="/tags/elasticsearch/" style="font-size: 10px;" class="tags-cloud-0">elasticsearch</a> <a href="/tags/fastdfs/" style="font-size: 10px;" class="tags-cloud-0">fastdfs</a> <a href="/tags/git/" style="font-size: 10px;" class="tags-cloud-0">git</a> <a href="/tags/go/" style="font-size: 12.5px;" class="tags-cloud-3">go</a> <a href="/tags/hexo/" style="font-size: 10px;" class="tags-cloud-0">hexo</a> <a href="/tags/idea/" style="font-size: 10px;" class="tags-cloud-0">idea</a> <a href="/tags/jvm/" style="font-size: 11.25px;" class="tags-cloud-1">jvm</a> <a href="/tags/kafka/" style="font-size: 11.25px;" class="tags-cloud-1">kafka</a> <a href="/tags/linux/" style="font-size: 15px;" class="tags-cloud-5">linux</a> <a href="/tags/maven/" style="font-size: 10px;" class="tags-cloud-0">maven</a> <a href="/tags/minio/" style="font-size: 11.25px;" class="tags-cloud-1">minio</a> <a href="/tags/mysql/" style="font-size: 13.75px;" class="tags-cloud-4">mysql</a> <a href="/tags/nginx/" style="font-size: 12.5px;" class="tags-cloud-3">nginx</a> <a href="/tags/node/" style="font-size: 10px;" class="tags-cloud-0">node</a> <a href="/tags/oracle/" style="font-size: 10px;" class="tags-cloud-0">oracle</a> <a href="/tags/pulsar/" style="font-size: 10px;" class="tags-cloud-0">pulsar</a> <a href="/tags/rabbitmq/" style="font-size: 17.5px;" class="tags-cloud-8">rabbitmq</a> <a href="/tags/redis/" style="font-size: 16.25px;" class="tags-cloud-6">redis</a> <a href="/tags/redis-%E4%BA%8B%E5%8A%A1/" style="font-size: 10px;" class="tags-cloud-0">redis,事务</a> <a href="/tags/rocketmq/" style="font-size: 17.5px;" class="tags-cloud-8">rocketmq</a> <a href="/tags/shell/" style="font-size: 10px;" class="tags-cloud-0">shell</a> <a href="/tags/spring/" style="font-size: 10px;" class="tags-cloud-0">spring</a> <a href="/tags/tomcat/" style="font-size: 10px;" class="tags-cloud-0">tomcat</a> <a href="/tags/vim/" style="font-size: 10px;" class="tags-cloud-0">vim</a> <a href="/tags/yml/" style="font-size: 10px;" class="tags-cloud-0">yml</a> <a href="/tags/zookeeper/" style="font-size: 10px;" class="tags-cloud-0">zookeeper</a> <a href="/tags/%E4%B8%87%E5%B9%B4%E5%8F%B0/" style="font-size: 10px;" class="tags-cloud-0">万年台</a> <a href="/tags/%E4%B8%AD%E9%97%B4%E4%BB%B6/" style="font-size: 18.75px;" class="tags-cloud-9">中间件</a> <a href="/tags/%E4%BA%8B%E5%8A%A1/" style="font-size: 10px;" class="tags-cloud-0">事务</a> <a href="/tags/%E5%8A%A0%E5%AF%86/" style="font-size: 13.75px;" class="tags-cloud-4">加密</a> <a href="/tags/%E5%93%A8%E5%85%B5/" style="font-size: 10px;" class="tags-cloud-0">哨兵</a> <a href="/tags/%E5%B7%A5%E5%85%B7/" style="font-size: 11.25px;" class="tags-cloud-1">工具</a> <a href="/tags/%E5%B8%B8%E7%94%A8%E7%AE%97%E6%B3%95/" style="font-size: 16.25px;" class="tags-cloud-6">常用算法</a> <a href="/tags/%E5%B9%B6%E5%8F%91/" style="font-size: 10px;" class="tags-cloud-0">并发</a> <a href="/tags/%E6%96%87%E4%BB%B6%E5%AD%98%E5%82%A8/" style="font-size: 11.25px;" class="tags-cloud-1">文件存储</a> <a href="/tags/%E7%B4%A2%E5%BC%95/" style="font-size: 10px;" class="tags-cloud-0">索引</a> <a href="/tags/%E9%94%81%E6%9C%BA%E5%88%B6/" style="font-size: 10px;" class="tags-cloud-0">锁机制</a> <a href="/tags/%E9%97%AE%E9%A2%98/" style="font-size: 10px;" class="tags-cloud-0">问题</a>
    </div>
  </div>
</section>
    </div>
  </article>
</div>
<script>
	//解决中文转义无法跳转锚点问题
	var blog = document.querySelector("#blog-content");
	var content = blog.innerHTML;
	var regExp2 = /<h([1-6]) id=\"(\S*?)\">/g;
	var	data = content.replace(regExp2, function(word,i){
		var ws = word.split("\"");
			return ws[0]+"\""+encodeURIComponent(ws[1])+"\""+ws[2];
		},"g");
	blog.innerHTML = data;
</script>

    <!-- footer container -->
<footer id="footer" class="footer">
  <div class="footer-container">
    
    <div class="social-icons">
      
        
          <a href="https://music.163.com/#/user/home?id=444731906" class="soft-size--primary soft-style--box" target="_blank" rel="noopener noreferrer">
            <svg class="icon icon-<%= icon %>" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">
    <path d="M952.17867 503.263237a341.054956 341.054956 0 0 0-56.853199-113.706399 408.604266 408.604266 0 0 0-109.723463-98.352823 304.662484 304.662484 0 0 0-143.257215-42.077792L621.305897 170.238394a40.343287 40.343287 0 0 1 10.792472-36.392472 56.88532 56.88532 0 0 1 36.392472-18.758344 102.785445 102.785445 0 0 1 56.853199 18.758344c6.263488 3.404768 10.792472 9.090088 17.05596 13.073024a57.335006 57.335006 0 0 0 82.999247-70.632873 66.521455 66.521455 0 0 0-22.74128-27.848432 237.691343 237.691343 0 0 0-89.262735-43.202007A170.559598 170.559598 0 0 0 625.288833 6.42409a167.026349 167.026349 0 0 0-60.836135 37.516688 164.328231 164.328231 0 0 0-40.921456 51.713927 156.908407 156.908407 0 0 0-8.54404 113.706399l13.651192 52.870264a284.298118 284.298118 0 0 0-158.064743 109.209535 256.963614 256.963614 0 0 0-43.202007 156.908407 248.419573 248.419573 0 0 0 13.651192 74.487327 205.281807 205.281807 0 0 0 80.718695 104.616312 185.945295 185.945295 0 0 0 136.447679 25.696361 193.879046 193.879046 0 0 0 156.330238-196.705646L708.802008 503.263237c-11.948808-46.060728-24.443664-91.543287-35.814304-137.025847a182.283563 182.283563 0 0 1 47.763112 18.180176 316.611292 316.611292 0 0 1 47.763111 34.690088A239.907654 239.907654 0 0 1 840.752823 529.987453a284.169636 284.169636 0 0 1 0 158.064743 252.241907 252.241907 0 0 1-21.584943 51.167879 308.741782 308.741782 0 0 1-168.279047 144.542033 387.918695 387.918695 0 0 1-130.184191 23.319448 332.607277 332.607277 0 0 1-155.206022-37.516688A367.233124 367.233124 0 0 1 194.87478 672.666499a373.014806 373.014806 0 0 1-20.460727-180.806022A366.173149 366.173149 0 0 1 406.869762 198.536512a57.399247 57.399247 0 0 0 13.073023-100.055207 76.189711 76.189711 0 0 0-63.662735-3.404768A479.815307 479.815307 0 0 0 68.705646 436.163614a488.905395 488.905395 0 0 0 129.027855 450.84266 454.857716 454.857716 0 0 0 248.997741 131.886574 470.885822 470.885822 0 0 0 138.117942 0A454.889837 454.889837 0 0 0 773.042911 952.949561a427.523212 427.523212 0 0 0 170.559598-209.232622 417.276788 417.276788 0 0 0 22.74128-109.209536 378.089837 378.089837 0 0 0-14.165119-131.244166z m-412.747804 118.845671a72.174655 72.174655 0 0 1-56.8532-10.792471 98.352823 98.352823 0 0 1-37.516687-61.382184 170.68808 170.68808 0 0 1 0-65.943287 133.042911 133.042911 0 0 1 33.533751-63.662735 181.35207 181.35207 0 0 1 80.718695-46.606776l39.219072 148.364367a204.189711 204.189711 0 0 1 5.107152 26.146048 79.594479 79.594479 0 0 1-64.208783 73.844918z"></path>
  </svg>
          </a>
        
      
        
          <a href="https://www.zhihu.com" class="soft-size--primary soft-style--box" target="_blank" rel="noopener noreferrer">
            <svg t="1587373160860" class="icon icon-zhihu" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <path d="M544.949 561.422s0-71.387-34.779-75.050c-34.779-3.663-142.775 0-142.775 0v-219.654h161.078s-1.83-73.219-32.949-73.219h-261.755l43.93-117.148s-65.897 3.663-89.692 45.761-98.844 252.604-98.844 252.604 25.627 10.983 67.726-20.134c42.101-31.116 56.743-86.033 56.743-86.033l76.879-3.663 1.83 223.316s-133.621-1.83-161.078 0c-27.457 1.83-42.101 75.050-42.101 75.050h203.182s-18.307 124.47-69.557 214.164c-53.085 89.692-151.929 161.078-151.929 161.078s71.387 29.287 140.947-10.983c69.557-42.101 120.811-223.316 120.811-223.316l162.912 203.182s14.643-97.013-1.83-124.47c-18.307-27.457-113.49-137.283-113.49-137.283l-42.101 36.607 29.287-120.811h177.552zM587.050 188.010l-1.83 660.793h65.897l23.795 82.37 115.321-82.37h162.912v-660.793h-366.091zM879.92 775.584h-76.879l-97.013 75.050-21.965-75.050h-20.134v-512.527h215.991v512.527z"></path>
</svg>
          </a>
        
      
        
          <a href="https://gitee.com/RocPengHua" class="soft-size--primary soft-style--box" target="_blank" rel="noopener noreferrer">
            <svg class="icon icon-<%= icon %>" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">
    <path d="M512 1024C229.248 1024 0 794.752 0 512S229.248 0 512 0s512 229.248 512 512-229.248 512-512 512z m259.168-568.896h-290.752a25.28 25.28 0 0 0-25.28 25.28l-0.032 63.232c0 13.952 11.296 25.28 25.28 25.28h177.024a25.28 25.28 0 0 1 25.28 25.28v12.64a75.84 75.84 0 0 1-75.84 75.84h-240.224a25.28 25.28 0 0 1-25.28-25.28v-240.192a75.84 75.84 0 0 1 75.84-75.84h353.92a25.28 25.28 0 0 0 25.28-25.28l0.064-63.2a25.312 25.312 0 0 0-25.28-25.312H417.184a189.632 189.632 0 0 0-189.632 189.6v353.952c0 13.952 11.328 25.28 25.28 25.28h372.928a170.656 170.656 0 0 0 170.656-170.656v-145.376a25.28 25.28 0 0 0-25.28-25.28z" p-id="1954"></path>
  </svg>
          </a>
        
      
        
          <a href="https://github.com/RocPengHua" class="soft-size--primary soft-style--box" target="_blank" rel="noopener noreferrer">
            <svg class="icon icon-github" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <path d="M64.6 512c0 195.6 125.4 361.9 300.1 422.9 23.5 5.9 19.9-10.8 19.9-22.2v-77.6c-135.8 15.9-141.3-74-150.5-89-18.5-31.5-61.9-39.5-49-54.5 31-15.9 62.5 4 98.9 58 26.4 39.1 77.9 32.5 104.1 26 5.7-23.5 17.9-44.5 34.7-60.9-140.7-25.2-199.4-111.1-199.4-213.3 0-49.5 16.4-95.1 48.4-131.8-20.4-60.6 1.9-112.4 4.9-120.1 58.2-5.2 118.5 41.6 123.3 45.3 33.1-8.9 70.8-13.7 112.9-13.7 42.4 0 80.3 4.9 113.5 13.9 11.3-8.6 67.3-48.8 121.4-43.9 2.9 7.7 24.7 58.3 5.5 118.1 32.5 36.8 49 82.8 49 132.4 0 102.3-59 188.3-200.2 213.2 23.5 23.3 38.1 55.5 38.1 91.1v112.7c0.8 9 0 17.9 15.1 17.9C832.7 877 960.4 709.4 960.4 512.1c0-247.5-200.6-447.9-447.9-447.9C265 64.1 64.6 264.5 64.6 512z"></path>
</svg>
          </a>
        
      
        
          <a href="https://twitter.com/guanquanhong" class="soft-size--primary soft-style--box" target="_blank" rel="noopener noreferrer">
            <svg class="icon icon-twitter" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <path d="M962.285714 233.142857q-38.285714 56-92.571429 95.428571 0.571429 8 0.571429 24 0 74.285714-21.714286 148.285714t-66 142-105.428571 120.285714-147.428571 83.428571-184.571429 31.142857q-154.857143 0-283.428571-82.857143 20 2.285714 44.571429 2.285714 128.571429 0 229.142857-78.857143-60-1.142857-107.428571-36.857143t-65.142857-91.142857q18.857143 2.857143 34.857143 2.857143 24.571429 0 48.571429-6.285714-64-13.142857-106-63.714286t-42-117.428571l0-2.285714q38.857143 21.714286 83.428571 23.428571-37.714286-25.142857-60-65.714286t-22.285714-88q0-50.285714 25.142857-93.142857 69.142857 85.142857 168.285714 136.285714t212.285714 56.857143q-4.571429-21.714286-4.571429-42.285714 0-76.571429 54-130.571429t130.571429-54q80 0 134.857143 58.285714 62.285714-12 117.142857-44.571429-21.142857 65.714286-81.142857 101.714286 53.142857-5.714286 106.285714-28.571429z"></path>
</svg>
          </a>
        
      
    </div>
     
    <p>&copy; 2024 <a href="/" target="_blank">RocPengHua</a></p>

    

    <p>Powered by <a href="https://hexo.io" target="_blank" rel="noopener noreferrer">Hexo</a> Theme - <a href="https://github.com/miiiku/flex-block" target="_blank" rel="noopener noreferrer author">flex-block</a></p>

    <p>
      <a href="javascript:;" id="theme-light">🌞 浅色</a>
      <a href="javascript:;" id="theme-dark">🌛 深色</a>
      <a href="javascript:;" id="theme-auto">🤖️ 自动</a>
    </p>
  </div>
</footer>
  </div>

  <div class="back-to-top-fixed soft-size--round soft-style--box">
    <svg class="icon icon-back-to-top" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">
      <path d="M725.333333 426.666667c-12.8 0-21.333333-4.266667-29.866667-12.8l-213.333333-213.333333c-17.066667-17.066667-17.066667-42.666667 0-59.733333s42.666667-17.066667 59.733333 0l213.333333 213.333333c17.066667 17.066667 17.066667 42.666667 0 59.733333C746.666667 422.4 738.133333 426.666667 725.333333 426.666667z"></path>
      <path d="M298.666667 426.666667c-12.8 0-21.333333-4.266667-29.866667-12.8-17.066667-17.066667-17.066667-42.666667 0-59.733333l213.333333-213.333333c17.066667-17.066667 42.666667-17.066667 59.733333 0s17.066667 42.666667 0 59.733333l-213.333333 213.333333C320 422.4 311.466667 426.666667 298.666667 426.666667z"></path>
      <path d="M512 896c-25.6 0-42.666667-17.066667-42.666667-42.666667L469.333333 170.666667c0-25.6 17.066667-42.666667 42.666667-42.666667s42.666667 17.066667 42.666667 42.666667l0 682.666667C554.666667 878.933333 537.6 896 512 896z"></path>
    </svg>
  </div>

  
  <!-- aplayer -->


<!-- dplayer -->




  


  


  <!-- Baidu Analytics START -->
  <script>
    var _hmt = _hmt || [];
    (function () {
      if (window.location.hostname === "localhost" || window.location.hostname.startsWith("192.168")) {
        return console.log("本地调试");
      }
      var hm = document.createElement("script");
      hm.src = "https://hm.baidu.com/hm.js?true";
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(hm, s);
    })();
  </script>
  <!-- Baidu Analytics End -->

  




<script src="/js/script.js"></script>


  
  <link rel="stylesheet" href="/lib/aplayer/APlayer.min.css">
<script type="text/javascript" src="/lib/aplayer/APlayer.min.js"></script>
<script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="/js/search.js"></script>

<!-- Calendar -->

    <script src="/js/calendar.js"></script>
    <script src="/js/languages.js"></script>
    <script type="text/javascript">
        $(function() {
            $('#calendar').aCalendar(
                'zh-CN',
                {single:false, root:'calendar/'}
            );
        });
    </script>

<!-- 尾部用户自定义相关内容 -->
<div id="aplayer"></div>
<script type="text/javascript">

	/*获取音乐*/
	$.get("https://api.i-meto.com/meting/api?server=netease&type=playlist&id=3778678&r=0.37201068616290645", function(result){
		if(result && result.code  == 50000){
			console.log(result.msg);
			return;
		}
	    const ap = new APlayer({
	    container: document.getElementById('aplayer'),
	    global:true,
	    id:'3778678',
	    server: 'netease',
	    type: 'paylist',
	    fixed: true,
	    preload: 'none',
	    theme: '#ffa500',
	    autoplay: false,
	    audio: result
	  });
	});










	/*图片放大js*/
	function createImgEventFullScreen() {
        var imgs = $(".post-container").find("img");
        for (var i = 0; i < imgs.length; i++) {
            // $(imgs[i]).click(createCover(imgs[i]));
            imgs[i].onclick = function (e) {
                var src = e.srcElement.currentSrc;
                var _this = $(this);
                console.log(_this);
                createCover(src,_this);
            }
        }
        function createCover(src,_this) {
            console.log(_this);
            console.log(src);
            var cover = $("<div id='outerDiv'  style='position:fixed;top:0;left:0;background:rgba(0,0,0,0.7);z-index:5;width:100%;height:100%;display:none;'><div id='innerDiv' style='position:absolute;'><img  id='bigImg' style='border:5px solid #fff;' src=''/></div></div>");
            $("#outerDiv").remove();
            $("body").append(cover);
            imgShow("#outerDiv", "#innerDiv", "#bigImg", _this,src);

        }
    }
    function imgShow(outerDiv, innerDiv, bigImg, _this,src) {
        //var src = _this.attr("src"); //获取当前点击的common-img元素中的src属性
        $(bigImg).attr("src", src); //设置#bigImg元素的src属性

        /*获取当前点击图片的真实大小，并显示弹出层及大图*/
        $("<img/>").attr("src", src).on('load',function () {
            var windowW = $(window).width(); //获取当前窗口宽度
            var windowH = $(window).height(); //获取当前窗口高度
            var realWidth = this.width; //获取图片真实宽度
            var realHeight = this.height; //获取图片真实高度
            var imgWidth, imgHeight;
            var scale = 0.8; //缩放尺寸，当图片真实宽度和高度大于窗口宽度和高度时进行缩放

            if (realHeight > windowH * scale) { //判断图片高度
                imgHeight = windowH * scale; //如大于窗口高度，图片高度进行缩放
                imgWidth = imgHeight / realHeight * realWidth; //等比例缩放宽度
                if (imgWidth > windowW * scale) { //如宽度仍大于窗口宽度
                    imgWidth = windowW * scale; //再对宽度进行缩放
                }
            } else if (realWidth > windowW * scale) { //如图片高度合适，判断图片宽度
                imgWidth = windowW * scale; //如大于窗口宽度，图片宽度进行缩放
                imgHeight = imgWidth / realWidth * realHeight; //等比例缩放高度
            } else { //如果图片真实高度和宽度都符合要求，高宽不变
                imgWidth = realWidth;
                imgHeight = realHeight;
            }
            $(bigImg).css("width", imgWidth); //以最终的宽度对图片缩放

            var w = (windowW - imgWidth) / 2; //计算图片与窗口左边距
            var h = (windowH - imgHeight) / 2; //计算图片与窗口上边距
            $(innerDiv).css({ "top": h, "left": w }); //设置#innerDiv的top和left属性
            //console.log('****')
            $(outerDiv).fadeIn("fast"); //淡入显示#outerDiv
        });

        $(outerDiv).click(function () { //再次点击淡出消失弹出层
            $(this).fadeOut("fast");
        });
    }
    setTimeout(function () {
        createImgEventFullScreen();
    }, 1000)
</script>
<style>
.aplayer.aplayer-fixed.aplayer-narrow .aplayer-body{
	width: 0px!important
}
.aplayer.aplayer-narrow .aplayer-body, .aplayer.aplayer-narrow .aplayer-pic {
	width: 0px!important
}
</style>
</body>
</html>